home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Mail / pine3.92 / pico / mswin.c < prev    next >
C/C++ Source or Header  |  1996-03-17  |  220KB  |  9,245 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: mswin.c,v 4.57 1996/03/18 04:10:42 mikes Exp $";
  3. #endif
  4. /*---------------------------------------------------------------------------
  5.  *
  6.  *  Module: mswin.c
  7.  *
  8.  * Thomas Unger
  9.  * Networks and Distributed Computing
  10.  * Computing and Communications
  11.  * University of Washington
  12.  * Administration Builiding, AG-44
  13.  * Seattle, Washington, 98195, USA
  14.  * Internet: tunger@cac.washington.edu
  15.  *
  16.  *
  17.  * Pine and Pico are registered trademarks of the University of Washington.
  18.  * No commercial use of these trademarks may be made without prior written
  19.  * permission of the University of Washington.
  20.  * 
  21.  * Pine, Pico, and Pilot software and its included text are Copyright
  22.  * 1989-1996 by the University of Washington.
  23.  * 
  24.  * The full text of our legal notices is contained in the file called
  25.  * CPYRIGHT, included with this distribution.
  26.  *--------------------------------------------------------------------------*/
  27.  
  28. #define WIN31 
  29. #define STRICT
  30.  
  31. #include <windows.h>
  32. #include <commdlg.h>
  33. #ifndef    WIN32
  34. #include <print.h>
  35. #include <toolhelp.h>
  36. #endif
  37. #include <cderr.h>
  38. #include <winsock.h>
  39. #include <shellapi.h>
  40.  
  41. #include <limits.h>
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include <stdarg.h>
  45. #include <errno.h>
  46. #include <signal.h>
  47. #include <setjmp.h>
  48. /*#include <conio.h>*/
  49. #include <time.h>
  50. /*#include <signal.h>*/
  51. #include <fcntl.h>
  52.  
  53. #define    termdef    1            /* don't define "term" external */
  54.  
  55. #include "osdep.h"
  56. #include "pico.h"
  57. #include "estruct.h"
  58. #include "efunc.h"
  59. #include "edef.h"
  60. #include "msmenu.h"
  61.  
  62.  
  63. /* Windows only version and resource defines. */
  64. #include "resource.h"
  65.  
  66.  
  67.  
  68.  
  69. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  70.  *
  71.  *            Defines
  72.  *
  73.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  74.  
  75.  
  76. #define ICON
  77.  
  78.  
  79. /* For debugging, export locals so debugger can see them. */
  80. #ifdef DEBUG
  81. #define LOCAL
  82. #else
  83. #define LOCAL        static
  84. #endif
  85.  
  86.  
  87. /* 
  88.  * Define which debugging is deisred.  Generally only FDEBUG. 
  89.  */
  90. #define FDEBUG        /* Standard file debugging. */
  91.  
  92. #undef SDEBUG        /* Verbose debugging of startup and windows handling*/
  93. #undef CDEBUG        /* Verbose debugging of character input timeing. */
  94.  
  95. #undef OWN_DEBUG_FILE    /* Define if we want to write to our own debug file, 
  96.              * not pine's. */
  97.  
  98.  
  99.  
  100.  
  101. /* Max size permitted for the screen.  Larger than ever expec, but small
  102.  * enough to prevent errors.  And small enough that the size of the
  103.  * screen strucure is less than 64K. */
  104. #define MAXNROW            180
  105. #define MAXNCOLUMN        256
  106.  
  107. #define MINNROW            10    /* Minimum screen size */
  108. #define MINNCOLUMN        32
  109.  
  110. #define MARGINE_LEFT        3
  111. #define MARGINE_TOP        1
  112.  
  113. #define FRAME_3D_SIZE        1
  114.  
  115. #define WIN_MIN_X_SIZE        190    /* Minimum window size. */
  116. #define WIN_MIN_Y_SIZE        180
  117.  
  118. #define WIN_X_BORDER_SIZE    8    /* Space taked by window frame. */
  119. #define WIN_Y_BORDER_SIZE    65
  120.  
  121. #define FONT_MIN_SIZE        5
  122. #define FONT_MAX_SIZE        21
  123.  
  124. #define PRINT_TAB_SIZE        8    /* Tab size used by print code. */
  125.  
  126.  
  127. #define TB_HEIGHT        32    /* Tool Bar Height. */
  128. #define TB_BUTTONHEIGHT        16    /* Button Height. */
  129. #define TB_BUTTONSPACING    8    /* Space between buttons. */
  130.  
  131.  
  132.  
  133.  
  134.  
  135. /* Some string lengths. */
  136. #define MAXLEN_TEMPSTR        256    /* Max size for temp storage. */
  137.  
  138. #define WIN_POS_STR_MAX_LEN    20    /* Max length for window-position
  139.                      * string. */
  140.  
  141. #define MENU_ITEM_NAME_LEN    32    /* Menu item name lengths. */
  142.  
  143.  
  144.  
  145.  
  146. /* Length of keyboard input queue. */
  147. #define CHARACTER_QUEUE_LENGTH    32
  148. #define MOUSE_QUEUE_LENGTH    32
  149.  
  150.  
  151. /* Number of resize callback functions we can keep track of. */
  152. #define RESIZE_CALLBACK_ARRAY_SIZE    3
  153.  
  154.  
  155. /* Number of bytes held in the write accumulator. */
  156. #define WRITE_ACCUM_SIZE        200
  157.  
  158.  
  159.  
  160. /* Max time that may pass between calls to GetMessage.  See mswin_charavail()
  161.  */
  162. #define GM_MAX_TIME    3000        /* In milliseconds.*/
  163.  
  164.  
  165. /* My Timer Message */
  166. #define MY_TIMER_ID    33
  167. #define MY_TIMER_PERIOD (UINT)60000    /* timeout period in miliseconds. */
  168. #define MY_TIMER_SHORT_PERIOD (UINT)5000  /* used when there is a task in
  169.                          the OnTask list. */
  170. #define MY_TIMER_VERY_SHORT_PERIOD (UINT)500  /* used when SIGALRM and alarm()
  171.                          is set. */
  172. #define MY_TIMER_EXCEEDINGLY_SHORT_PERIOD (UINT)80 /* used when 
  173.                          gAllowMouseTracking is set */
  174.  
  175. #define TIMER_FAIL_MESSAGE "Failed to get all necessary Windows resoruce (timers).  Pine will run, but may not be able to keep the connection to the server alive.  Quiting other applications and restarting Pine may solve the problem."
  176.  
  177.  
  178.  
  179.  
  180. /*
  181.  * Below here are fixed constancs that really should not be changed.
  182.  */
  183.  
  184. /* Cursor states. */
  185. #define CS_SHOW         0x01        /* Cursor is not hidden. */
  186. #define CS_FOCUSED    0x02        /* Window is focused. */
  187. #define CS_VISIBLE    0x03        /* When above two bits set, cursor is
  188.                      * visible. */
  189.  
  190. /* Auto Wrap States. */
  191. #define WRAP_OFF    0        /* Never wrap to next line. */
  192. #define WRAP_ON        1        /* Wrap to next line. */
  193. #define WRAP_NO_SCROLL    2        /* Wrap to next line but DON'T scroll
  194.                        screen to do it. */
  195.  
  196. /* Speicial keys in the Character Queue. */
  197. #define CQ_FLAG_DOWN        0x01
  198. #define CQ_FLAG_EXTENDED    0x02
  199. #define CQ_FLAG_ALT        0x04
  200.  
  201.  
  202.  
  203. /* Special ASCII characters. */
  204. #define ASCII_BEL       0x07
  205. #define ASCII_BS        0x08
  206. #define ASCII_TAB    0x09
  207. #define ASCII_LF        0x0A
  208. #define ASCII_CR        0x0D
  209. #define ASCII_XON       0x11
  210. #define ASCII_XOFF      0x13
  211.  
  212.  
  213.  
  214.  
  215. /* Character Attributes. */
  216. #define CHAR_ATTR_NORM    0x00        /* Normal. */
  217. #define CHAR_ATTR_REV    0x01        /* Reverse Video. */
  218. #define CHAR_ATTR_SEL    0x02        /* Selected text. */
  219. #define CHAR_ATTR_NOT   0x80        /* No attributes. */
  220.  
  221.  
  222. /*
  223.  * Different applications that we know about.
  224.  */
  225. #define APP_UNKNOWN        0
  226. #define APP_PICO        1
  227. #define APP_PICO_IDENT        "pico"
  228. #define APP_PINE        2
  229. #define APP_PINE_IDENT        "pine"
  230.  
  231.  
  232.  
  233. /*
  234.  * Control values for call to AccelCtl.
  235.  */
  236. #undef ACCELERATORS
  237. #define ACCEL_UNLOAD        0    /* Unload the accelerators. */
  238. #define ACCEL_LOAD        1    /* Load the accelerators. */
  239. #define ACCEL_TOGGLE        2    /* Toggle the accelerators. */
  240.  
  241.  
  242.  
  243. /* Offsets to objects in window extra storage. */
  244. #define GWL_PTTYINFO        0    /* Offset in Window extra storage. */
  245. #define GWL_PTEXTINFO        0    /* Offset in Window extra storage. */
  246.  
  247. #define ABOUTDLG_USEBITMAP    1
  248.  
  249.  
  250.  
  251. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  252.  *
  253.  *            Typedefs
  254.  *
  255.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  256.  
  257. /* Type that the screen array is made up of. */
  258. #define    CHAR    unsigned char
  259.  
  260. /* Type that the attribute array is made up of. */
  261. typedef BYTE            CharAttrib;
  262. typedef int            (*ResizeCallBackProc)();
  263. typedef    int            (*FileDropCallBackProc)();
  264. typedef short            CORD;
  265.  
  266.  
  267. /* NOTE:  There is currently code that assumes that CHAR and CharAttrib
  268.  *    are one byte in size.  All this code is flaged with a preceeding
  269.  *    assert () */
  270.  
  271.  
  272. /* Struct that defines command menu entries. */
  273. typedef struct tagMenuItem {
  274.     BOOL    miActive;
  275.     WORD    miKey;
  276. } MenuItem;
  277.  
  278.  
  279. /* List of child window IDs and previous window procedures. */
  280. typedef struct tagBtnList {
  281.     WORD    wndID;
  282.     WNDPROC    wndProc;
  283. } BtnList;
  284.  
  285.  
  286. /* General info. */
  287. typedef struct tagTTYINFO {
  288.     CHAR    *pScreen;    /* Screen. */
  289.     BYTE    *pAttrib;    /* Attributes. */
  290.     BOOL    screenDirty;    /* TRUE if screen needs update. */
  291.     BOOL    eraseScreen;    /* TRUE if need to erase whole screen */
  292.     CHAR    writeAccum[WRITE_ACCUM_SIZE];
  293.     int        writeAccumCount;
  294.     WORD    wCursorState;    /* Is cursor displayed? */
  295.     int        scrollRange;    /* Current scroll bar range. */
  296.     long    scrollPos;    /* Current scroll position. */
  297.     long    scrollTo;    /* Possition of last scroll to. */
  298.     float    scrollScale;    /* Scaleing for scroll range. */
  299.     HFONT    hTTYFont;
  300.     LOGFONT    lfTTYFont;
  301.     DWORD    rgbFGColor;    /* Normal forground color. */
  302.     DWORD    rgbBGColor;    /* Normal background color. */
  303.     DWORD    rgbRFGColor;    /* Reverse forground color. */
  304.     DWORD    rgbRBGColor;    /* Reverse background color */
  305.     BOOL    fMinimized;    /* True when window is minimized. */
  306.     BOOL    fFocused;    /* True when we have focus. */
  307.     BOOL    fNewLine;    /* Auto LF on CR. */
  308.     BOOL    fMassiveUpdate;    /* True when in Massive screen update. */
  309.     BOOL    fNewMailIcon;    /* True when new mail has arrived. */
  310.     ResizeCallBackProc  resizer[RESIZE_CALLBACK_ARRAY_SIZE];
  311.     FileDropCallBackProc dndhandler;
  312.     int        autoWrap;    /* Auto wrap to next line. */
  313.     CharAttrib    curAttrib;    /* Current character attributes. */
  314.     int        actNRow, actNColumn;    /* Actual number of rows and comumns
  315.                      * displayed. */
  316.     CORD    xSize, ySize;        /* Size of screen in pixels */
  317.     CORD    xScroll, yScroll;    /* ?? */
  318.     CORD    xOffset, yOffset;    /* Offset from the left and top of
  319.                      * window contents. */
  320.     CORD    nColumn, nRow;        /* Current position of cursor in 
  321.                          * cells. */
  322.     CORD    xChar, yChar;        /* Width of a char in pixels. */
  323.     CORD    fDesiredSize;        /* TRUE when there is a specific size
  324.                      * the window should be expanded to
  325.                      * after being minimized. */
  326.     CORD    xDesPos, yDesPos;    /* Desired position. */
  327.     CORD    xDesSize, yDesSize;    /* Desired window position. */
  328.     int        curWinMenu;        /* Current window menu. */
  329.     HACCEL    hAccel;            /* Handle to accelorator keys. */
  330.     CORD    toolBarSize;        /* Size of toolbar. */
  331.     BOOL    toolBarTop;        /* Toolbar on top? */
  332.     int        curToolBarID;
  333.     BtnList    *toolBarBtns;
  334.     HWND    hTBWnd;
  335.     BOOL    menuItemsCurrent;
  336.     MenuItem    menuItems[KS_COUNT];
  337. } TTYINFO, *PTTYINFO ;
  338.  
  339.  
  340.  
  341. typedef struct MSWINColor {
  342.     char        *colorName;
  343.     COLORREF        colorRef;
  344. } MSWINColor;
  345.  
  346.  
  347. /*
  348.  * Entry in the OnTask list.  This is a list of actions to perform
  349.  * when a task exits.  Currently, the only thing we do is delete
  350.  * files.  if that changes this structure will get more complex.
  351.  *
  352.  * hTask == NULL means "This program" and can be used to arrange for
  353.  * deletion of files when this program exits.
  354.  */
  355. typedef struct ontask {
  356.     struct ontask    *next;
  357.     HTASK        hTask;
  358.     char        path[PATH_MAX+1];
  359. } OnTaskItem;
  360.  
  361.  
  362. typedef void (__cdecl *SignalType)(int);
  363.  
  364.  
  365. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  366.  *
  367.  *            Forward function declarations.
  368.  *
  369.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  370.  
  371.  
  372.  
  373. #ifdef    WIN32
  374. #define    GET_HINST( hWnd )  ((HINSTANCE) GetWindowLong( hWnd, GWL_HINSTANCE ))
  375. #define    GET_ID( hWnd )  ((WORD) GetWindowLong( hWnd, GWL_ID ))
  376. #else
  377. #define GET_HINST( hWnd )  ((HINSTANCE) GetWindowWord( hWnd, GWW_HINSTANCE ))
  378. #define    GET_ID( hWnd )  ((WORD) GetWindowWord( hWnd, GWW_ID ))
  379. #endif
  380.  
  381. #define MIN(x,y)    ((x) < (y) ? (x) : (y))
  382. #define MAX(x,y)    ((x) > (y) ? (x) : (y))
  383. #define CONSTRAIN(v,min,max)    ((v) = (v) < (min) ? (min) : (v) > (max) ? (max) : (v))
  384.  
  385.  
  386. // function prototypes (private)
  387.  
  388. void        WinExit (void);
  389. LOCAL BOOL    InitApplication (HANDLE);
  390. LOCAL HWND    InitInstance (HANDLE, int);
  391. LOCAL void    MakeArgv (HINSTANCE hInstance, LPSTR cmdLine, int *pargc, 
  392.                 char ***pargv);
  393. LOCAL LRESULT NEAR    CreateTTYInfo (HWND hWnd);
  394. LOCAL BOOL NEAR    DestroyTTYInfo (HWND hWnd);
  395. LOCAL int    ResizeTTYScreen (HWND hWnd, PTTYINFO pTTYInfo, 
  396.                     int newNRow, int newNColumn);
  397. LOCAL BOOL    ResetTTYFont (HWND, PTTYINFO, LOGFONT *);
  398. LOCAL BOOL    EraseTTY (HWND, HDC);
  399. LOCAL BOOL    PaintTTY (HWND);
  400. LOCAL BOOL    GetMinMaxInfoTTY (HWND hWnd, MINMAXINFO __far *lpmmi);
  401. LOCAL BOOL    AboutToSizeTTY (HWND hWnd, WINDOWPOS *winPos);
  402. LOCAL BOOL    SizeTTY (HWND, int, CORD, CORD);
  403. LOCAL void    FrameRect3D(HDC hdc, RECT * pRC, int width, BOOL raised);
  404. LOCAL void    FillRectColor(HDC hDC, RECT * pRC, COLORREF color);
  405.  
  406.  
  407. LOCAL BOOL    MoveTTY (HWND hWnd, int xPos, int yPos);
  408. LOCAL void    ScrollTTY (HWND hWnd, int wScrollCode, int nPos, HWND hScroll);
  409. BOOL CALLBACK    NoMsgsAreSent (void);
  410. LOCAL BOOL    SetTTYFocus (HWND);
  411. LOCAL BOOL    KillTTYFocus (HWND);
  412. LOCAL BOOL    MoveTTYCursor (HWND);
  413. LOCAL BOOL    ProcessTTYKeyDown (HWND hWnd, WORD bOut, DWORD keyData);
  414. LOCAL BOOL    ProcessTTYKeyUp (HWND hWnd, WORD key, DWORD keyData);
  415. LOCAL BOOL    ProcessTTYCharacter (HWND hWnd, WORD bOut, DWORD keyData);
  416. LOCAL BOOL    ProcessTTYMouse (int mevent, int button, CORD xPos, 
  417.                     CORD yPos, WPARAM keys);
  418. LOCAL BOOL    ProcessTTYFileDrop (HANDLE wParam);
  419. LOCAL void    ProcessTimer (void);
  420. LOCAL BOOL    WriteTTYBlock (HWND, LPSTR, int);
  421. LOCAL BOOL    WriteTTYText (HWND, LPSTR, int);
  422. LOCAL BOOL    WriteTTYChar (HWND, char);
  423.  
  424. LOCAL VOID    GoModalDialogBoxParam (HINSTANCE, LPCSTR, HWND, 
  425.                     DLGPROC, LPARAM);
  426. LOCAL BOOL    SelectTTYFont (HWND);
  427. LOCAL void    SetColorAttribute (COLORREF *cf, char *colorName);
  428. LOCAL BOOL    ConvertRGBString (char *colorName, COLORREF *cf);
  429. LOCAL BOOL    ScanInt (char *str, int min, int max, int *val);
  430.  
  431. LOCAL void    TBToggle (HWND);
  432. LOCAL void    TBPosToggle (HWND);
  433. LOCAL void    TBShow (HWND);
  434. LOCAL void    TBHide (HWND);
  435. LOCAL void    TBSwap (HWND, int);
  436.  
  437. #ifdef ACCELERATORS
  438. LOCAL void    AccelCtl (HWND hWnd, int ctl, BOOL saveChange);
  439. #endif
  440.  
  441. LOCAL void    SelStart (int nRow, int nColumn);
  442. LOCAL void    SelFinish (int nRow, int nColumn);
  443. LOCAL void    SelClear (void);
  444. LOCAL void    SelTrackXYMouse (int xPos, int yPos);
  445. LOCAL void    SelTrackMouse (int nRow, int nColumn);
  446. LOCAL BOOL    SelAvailable (void);
  447. LOCAL void    SelDoCopy (HANDLE hCB, DWORD lenCB);
  448.  
  449. LOCAL void    FlushWriteAccum (void);
  450.  
  451.  
  452.  
  453.         /* ... interface routines ... */
  454.  
  455.  
  456. void        ProcessMenuItem (HWND hWnd, WPARAM wParam);
  457.  
  458. void        AlarmDeliver (void);
  459. void        HUPDeliver (void);
  460.  
  461. void        PrintFontSameAs (HWND hWnd);
  462. void        PrintFontSelect (HWND hWnd);
  463. void        ExtractFontInfo (LOGFONT *pFont, char *fontName, 
  464.             int *fontSize, char *fontStyle, int ppi);
  465.  
  466. LOCAL void    DidResize (PTTYINFO pTTYInfo);
  467.  
  468. LOCAL void    UpdateMenu (HWND hWnd);
  469. LOCAL void    EditCut (void);
  470. LOCAL void    EditCopy (void);
  471. LOCAL void    EditCopyAppend (void);
  472. LOCAL void    EditDoCopyData (HANDLE hCB, DWORD lenCB);
  473. LOCAL void    EditPaste (void);
  474. LOCAL void    EditCancelPaste (void);
  475. LOCAL WORD    EditPasteGet (void);
  476. LOCAL BOOL    EditPasteAvailable (void);
  477.  
  478. LOCAL void    ShowHelp (void);
  479.  
  480. LOCAL void    MyTimerSet (void);
  481.  
  482. LOCAL void    ProcessOnTask (void);
  483. LOCAL void    ProcessOnExit (void);
  484.  
  485. LOCAL LRESULT    ConfirmExit (void);
  486.  
  487. LOCAL BOOL    TWErase (HWND hWnd, HDC hDC);
  488. LOCAL void    TWPaint (HWND hWnd);
  489. LOCAL void    TWScroll (HWND hWnd, int wScrollCode, int nPos);
  490. LOCAL BOOL    TWKeyDown (HWND hWnd, WORD key, DWORD keyData);
  491. LOCAL BOOL    TWMouseDown (HWND hWnd, int button, CORD xPos, CORD yPos, 
  492.             WPARAM keys);
  493. LOCAL BOOL    TWMouseUp (HWND hWnd, int button, CORD xPos, CORD yPos, 
  494.             WPARAM keys);
  495. LOCAL BOOL    TWMouseTrack (HWND hWnd, CORD xPos, CORD yPos);
  496. LOCAL BOOL    TWEditCopy (HWND hWnd);
  497.  
  498. LOCAL void    TWSetSize (HWND hWnd, UINT wParam, UINT height, UINT width);
  499. LOCAL void    TWPrint (HWND hWnd);
  500.  
  501.  
  502. LOCAL void    CQInit (void);
  503. LOCAL BOOL    CQAvailable (void);
  504. LOCAL BOOL    CQAdd (WORD c, DWORD keyData);
  505. LOCAL BOOL    CQAddUniq (WORD c, DWORD keyData);
  506. LOCAL WORD    CQGet ();
  507.  
  508. LOCAL void    MQInit (void);
  509. LOCAL BOOL    MQAvailable (void);
  510. LOCAL BOOL    MQAdd (int mevent, int button, int nRow, int nColumn, 
  511.                 int keys, int flags);
  512. LOCAL BOOL    MQGet (MEvent * pmouse);
  513. LOCAL BOOL    MQClear (int flag);
  514.  
  515. LOCAL int    MapVKtoMS (WORD c, WORD flags);
  516.  
  517.  
  518.  
  519. /* Functions exported to MS Windows. */
  520.  
  521. LRESULT FAR PASCAL __export PWndProc (HWND, UINT, WPARAM, LPARAM);
  522. LRESULT FAR PASCAL __export TWWndProc (HWND, UINT, WPARAM, LPARAM);
  523. BOOL FAR PASCAL __export ToolBarProc (HWND, UINT, WPARAM, LPARAM);
  524. LRESULT FAR PASCAL __export TBBtnProc (HWND, UINT, WPARAM, LPARAM);
  525. BOOL FAR PASCAL __export AboutDlgProc (HWND, UINT, WPARAM, LPARAM);
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  534.  *
  535.  *            Exported Globals
  536.  *
  537.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  538.  
  539.  
  540.  
  541. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  542.  *
  543.  *            Imported Globals
  544.  *
  545.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  546.  
  547.  
  548.  
  549. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  550.  *
  551.  *            Module globals.
  552.  *
  553.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  554.  
  555.  
  556. PTTYINFO        gpTTYInfo;
  557. HWND            ghTTYWnd;
  558. HINSTANCE        ghInstance;
  559. BOOL            gfUseDialogs;
  560. FILE            *mswin_debugfile = NULL;
  561. int            mswin_debug = 0;
  562. char            gszAppName[45];
  563.  
  564. LOCAL BOOL        gUse3DFrame = FALSE;
  565.  
  566. LOCAL char        TempBuf [MAXLEN_TEMPSTR];
  567.  
  568. LOCAL char        gszTTYClass[] = "PineWnd";
  569. LOCAL char        gszTextClass[] = "PineText";
  570. LOCAL int        gAppIdent = APP_UNKNOWN;
  571.  
  572. LOCAL HCURSOR        ghCursorArrow = NULL;
  573. LOCAL HCURSOR        ghCursorBusy = NULL;
  574. LOCAL HCURSOR        ghCursorCurrent = NULL;
  575.  
  576.  
  577.  
  578. /* Used for Pasting text. */
  579. LOCAL HANDLE        ghPaste = NULL;        /* Handle to Paste data. */
  580. LOCAL char        *gpPasteNext = NULL;    /* Pointer to current char. */
  581. LOCAL size_t        gPasteBytesRemain = 0;    /* Count of bytes left. */
  582. LOCAL BOOL        gPasteWasCR = FALSE;    /* Previous char was CR. */
  583. LOCAL int        gPasteEnabled = MSWIN_PASTE_DISABLE;
  584. LOCAL getc_t        gCopyCutFunction = NULL;
  585. LOCAL scroll_t        gScrollCallback = NULL;
  586. LOCAL BOOL        gScrolling = FALSE;    /* Keeps track of when we are
  587.                          * in scroll routine. */
  588. LOCAL BOOL        gMouseTracking = FALSE;    /* Keeps track of when we are
  589.                          * tracking the mouse. */
  590. LOCAL FARPROC        gWSBlockingProc = NULL;
  591. LOCAL DLGPROC        gToolBarProc = NULL;
  592. LOCAL WNDPROC        gTBBtnProc = NULL; 
  593.  
  594. LOCAL BOOL        gAllowCopy = FALSE;
  595. LOCAL BOOL        gAllowCut = FALSE;
  596.  
  597. LOCAL BOOL        gAllowMouseTrack = FALSE;/* Upper layer interested in
  598.                          * mouse tracking. */
  599. LOCAL MEvent        gMTEvent;
  600.  
  601. LOCAL BOOL        gKeyControlDown = FALSE;/* Keep track of the control
  602.                          * key position. */
  603.  
  604. LOCAL char        *gpHelpTitle;        /* Title of help. */
  605. LOCAL char        *gpHelpText;        /* Pointer to help text. */
  606. LOCAL size_t        gpHelpLen;        /* Length of text. */
  607. LOCAL char        **gpHelpLines;        /* Alternate view. */
  608. LOCAL BOOL        gfHelpMenu = FALSE;    /* TRUE when help menu 
  609.                          * installed. */
  610. LOCAL char        *gpCloseText;
  611.  
  612. LOCAL DWORD        gGMLastCall = 0;    /* Last time I called
  613.                          * GetMessage. */
  614. LOCAL OnTaskItem    *gOnTaskList = NULL;    /* Things to do when a task
  615.                          * exits. */
  616. LOCAL OnTaskItem    *gOnExitList = NULL;    /* Things to do when I 
  617.                          * exit. */
  618. LOCAL BOOL        gConfirmExit = FALSE;
  619. LOCAL HICON        ghNormalIcon = NULL;
  620. LOCAL HICON        ghNewMailIcon = NULL;
  621.  
  622. LOCAL int        gPrintFontSize;
  623. LOCAL char        gPrintFontName[LF_FACESIZE+1];
  624. LOCAL char        gPrintFontStyle[64];
  625. LOCAL BOOL        gPrintFontSameAs = TRUE;
  626.  
  627. LOCAL UINT        gTimerCurrentPeriod = 0;
  628.  
  629. LOCAL callback_t    gPeriodicCallback = NULL; /* Function to call. */
  630. LOCAL DWORD        gPeriodicCBTimeout = 0;   /* Time of next call. */
  631. LOCAL DWORD        gPeriodicCBTime = 0;      /* Delay between calls. */
  632.  
  633. /* Currently only implement one SIGNAL so only need single variable. */
  634. LOCAL SignalType    gSignalAlarm = SIG_DFL;
  635. LOCAL DWORD        gAlarmTimeout = 0;    /* Time alarm expires in 
  636.                          * seconds 
  637.                          * (GetTickCount()/1000) */
  638. LOCAL SignalType    gSignalHUP = SIG_DFL;
  639.  
  640.  
  641.  
  642. LOCAL MSWINColor  MSWINColorTable[] =  {
  643.     "black",    RGB(0,0,0),
  644.     "blue",        RGB(0,0,255),
  645.     "green",    RGB(0,255,0),
  646.     "cyan",        RGB(0,255,255),
  647.     "red",        RGB(255,0,0),
  648.     "magenta",    RGB(255,0,255),
  649.     "yellow",    RGB(255,255,0),
  650.     "white",    RGB(255,255,255),
  651.     "ltgray",    RGB(192,192,192),
  652.     "gray",        RGB(128,128,128),
  653.     "dkgray",    RGB(64,64,64),
  654.     NULL,        0,
  655. };
  656.  
  657.  
  658.  
  659.  
  660.  
  661.  
  662. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  663.  *
  664.  *            Windows Functions.
  665.  *
  666.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  667.  
  668. /*---------------------------------------------------------------------------
  669.  *  int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance,
  670.  *                      LPSTR lpszCmdLine, int nCmdShow )
  671.  *
  672.  *  Description:
  673.  *     This is the main window loop!
  674.  *
  675.  *  Parameters:
  676.  *     As documented for all WinMain() functions.
  677.  *
  678.  *--------------------------------------------------------------------------*/
  679.  
  680. int PASCAL
  681. WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  682.                     LPSTR lpszCmdLine, int nCmdShow )
  683. {
  684.     char        **argv;
  685.     int            argc;
  686.     MSG            msg;
  687.  
  688.     ghInstance = hInstance;
  689.     if (!hPrevInstance)
  690.     if (!InitApplication( hInstance ))
  691.         return ( FALSE ) ;
  692.     
  693. #ifdef OWN_DEBUG_FILE    /* Want to write to seperate memdebug.txt file. */
  694.     mswin_debugfile = fopen ("memdebug.txt", "w");
  695.     fprintf (mswin_debugfile, "Beginning of mswin debug log\n");
  696.     if (mswin_debugfile != NULL) {
  697.     mswin_debug = 4;
  698.     MemDebug (mswin_debug, mswin_debugfile);
  699.     fprintf (mswin_debugfile, "Show window as:  %d\n", nCmdShow);
  700.     fflush (mswin_debugfile);
  701.     }
  702. #endif
  703.  
  704.     if (NULL == (ghTTYWnd = InitInstance (hInstance, nCmdShow)))
  705.     return (FALSE);
  706.  
  707.  
  708.     MakeArgv (hInstance, lpszCmdLine, &argc, &argv);
  709.     
  710.     atexit (WinExit);
  711.     
  712.     app_main (argc, argv);
  713.  
  714.     return (TRUE);
  715. }
  716.  
  717.  
  718.  
  719. void
  720. WinExit (void)
  721. {
  722.     MSG            msg;
  723.     
  724.     if (ghTTYWnd == NULL)
  725.     return;
  726.     
  727.     /* Destroy main window and process remaining events. */
  728.     DestroyWindow (ghTTYWnd);
  729.     while (GetMessage (&msg, NULL, 0, 0)) {
  730.     TranslateMessage (&msg);
  731.     DispatchMessage (&msg);
  732.     }
  733.  
  734. #ifdef OWN_DEBUG_FILE
  735.     fclose (mswin_debugfile);
  736. #endif
  737.     /* Take one last look at the task list. */
  738.     ProcessOnTask ();
  739.     ProcessOnExit ();
  740.     if (gWSBlockingProc != NULL)
  741.     FreeProcInstance (gWSBlockingProc);
  742.     MemFreeAll ();
  743.     ghTTYWnd = NULL;
  744. }
  745.  
  746.  
  747.  
  748. /*---------------------------------------------------------------------------
  749.  *  BOOL  InitApplication( HANDLE hInstance )
  750.  *
  751.  *  Description:
  752.  *     First time initialization stuff.  This registers information
  753.  *     such as window classes.
  754.  *
  755.  *  Parameters:
  756.  *     HANDLE hInstance
  757.  *        Handle to this instance of the application.
  758.  *
  759.  *--------------------------------------------------------------------------*/
  760.  
  761. LOCAL BOOL  
  762. InitApplication (HANDLE hInstance)
  763. {
  764.     WNDCLASS  wndclass;
  765.     DWORD    vers;
  766.     int        winMajorVers;
  767.     int        winMinorVers;
  768.     
  769.     vers = GetVersion ();
  770.     winMajorVers = LOBYTE(LOWORD(vers));
  771.     winMinorVers = HIBYTE(LOWORD(vers));
  772.     gUse3DFrame =  winMajorVers > 3 || 
  773.             (winMajorVers == 3 && winMinorVers >= 95);
  774.     
  775.  
  776.     /* 
  777.      * Register tty window class.
  778.      */
  779.     wndclass.style =         0;//CS_NOCLOSE;
  780.     wndclass.lpfnWndProc =   PWndProc;
  781.     wndclass.cbClsExtra =    0;
  782.     wndclass.cbWndExtra =    sizeof (LONG);
  783.     wndclass.hInstance =     hInstance ;
  784.     wndclass.hIcon =         NULL;
  785.     wndclass.hCursor =       LoadCursor (NULL, IDC_ARROW);
  786.     wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  787.     wndclass.lpszMenuName =  MAKEINTRESOURCE (PINEMENU);
  788.     wndclass.lpszClassName = gszTTYClass ;
  789.  
  790.     if (!RegisterClass (&wndclass))
  791.         return (FALSE);
  792.  
  793.     
  794.     /* 
  795.      * Register tty window class.
  796.      */
  797.     wndclass.style =         CS_BYTEALIGNWINDOW;
  798.     wndclass.lpfnWndProc =   TWWndProc;
  799.     wndclass.cbClsExtra =    0;
  800.     wndclass.cbWndExtra =    sizeof (LONG);
  801.     wndclass.hInstance =     hInstance ;
  802.     wndclass.hIcon =         LoadIcon (hInstance, MAKEINTRESOURCE( PINEICON));
  803.     wndclass.hCursor =       LoadCursor (NULL, IDC_ARROW);
  804.     wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  805.     wndclass.lpszMenuName =  MAKEINTRESOURCE (TEXTWINMENU);
  806.     wndclass.lpszClassName = gszTextClass ;
  807.  
  808.     return (RegisterClass (&wndclass));
  809. }
  810.  
  811.  
  812.  
  813. /*---------------------------------------------------------------------------
  814.  *  HWND  InitInstance( HANDLE hInstance, int nCmdShow )
  815.  *
  816.  *  Description:
  817.  *     Initializes instance specific information.
  818.  *
  819.  *  Parameters:
  820.  *     HANDLE hInstance
  821.  *        Handle to instance
  822.  *
  823.  *     int nCmdShow
  824.  *        How do we show the window?
  825.  *
  826. /*--------------------------------------------------------------------------*/
  827.  
  828. LOCAL HWND  
  829. InitInstance (HANDLE hInstance, int nCmdShow)
  830. {
  831.     HWND  hTTYWnd;
  832.     char  appIdent[32];
  833.  
  834. #ifdef SDEBUG
  835.     if (mswin_debug >= 5) 
  836.     fprintf (mswin_debugfile, "InitInstance:::  entered, nCmdShow %d\n",
  837.         nCmdShow);
  838. #endif
  839.  
  840.     LoadString (hInstance, IDS_APPNAME, gszAppName, sizeof (gszAppName));
  841.  
  842.     /* create the TTY window */
  843.     hTTYWnd = CreateWindow (gszTTYClass, gszAppName,
  844.                WS_OVERLAPPEDWINDOW | WS_VSCROLL,
  845.                CW_USEDEFAULT, CW_USEDEFAULT,
  846.                CW_USEDEFAULT, CW_USEDEFAULT,
  847.                HWND_DESKTOP, NULL, hInstance, NULL);
  848.            
  849.     SetScrollRange (hTTYWnd, SB_VERT, 0, 1, FALSE);
  850.     EnableScrollBar (hTTYWnd, SB_VERT, ESB_DISABLE_BOTH);
  851.     SetScrollPos (hTTYWnd, SB_VERT, 0, FALSE);
  852.  
  853.     
  854.     
  855.  
  856.     if (NULL == hTTYWnd) 
  857.         return (NULL);
  858.  
  859.     ghTTYWnd = hTTYWnd;
  860.  
  861.     ghNormalIcon = LoadIcon (hInstance, MAKEINTRESOURCE (PINEICON));
  862.     ghNewMailIcon = LoadIcon (hInstance, MAKEINTRESOURCE (NEWMAILICON));
  863.  
  864.     ghCursorArrow = LoadCursor (NULL, IDC_ARROW);
  865.     ghCursorBusy = LoadCursor (NULL, IDC_WAIT);
  866.     ghCursorCurrent = ghCursorArrow;
  867.     
  868.     
  869.  
  870.     ShowWindow (hTTYWnd, nCmdShow);
  871.     UpdateWindow (hTTYWnd);
  872.  
  873.     CQInit ();
  874.     MQInit ();
  875.  
  876.     
  877.     /*
  878.      * Load a resource with the name of the application.  Compare to 
  879.      * known applications to determine who we are running under.
  880.      * currently, only differentiation is the WINSOCK blocking hook.
  881.      */
  882.     LoadString (hInstance, IDS_APPIDENT, appIdent, sizeof (appIdent));
  883.     if (strcmp (appIdent, APP_PINE_IDENT) == 0) {
  884.     gAppIdent = APP_PINE;
  885.     gWSBlockingProc = MakeProcInstance ( (FARPROC) NoMsgsAreSent,
  886.                           hInstance);
  887.     }
  888.     else if (strcmp (appIdent, APP_PICO_IDENT) == 0) 
  889.     gAppIdent = APP_PICO;
  890.     else
  891.     gAppIdent = APP_UNKNOWN;
  892.  
  893.  
  894.     return (hTTYWnd);
  895. }
  896.  
  897.  
  898. /*---------------------------------------------------------------------------
  899.  *  void MakeArgv ()
  900.  *
  901.  *  Description:
  902.  *    Build a standard C argc, argv pointers into the command line string.
  903.  *
  904.  *
  905.  *  Parameters:
  906.  *    cmdLine        - Command line.
  907.  *    *argc        - Count of words.
  908.  *    ***argc        - Pointer to Pointer to array of pointers to 
  909.  *              characters.
  910.  *
  911.  *--------------------------------------------------------------------------*/
  912. LOCAL void
  913. MakeArgv (HINSTANCE hInstance, LPSTR cmdLine, int *pargc, char ***pargv)
  914. {
  915.     int            argc;
  916.     char        **argv;
  917.     LPSTR        c;
  918.     BOOL        inWord;
  919.     int            wordCount;
  920. #define CMD_PATH_LEN    128
  921.     char        *modPath;
  922.     char        mpLen;
  923.     
  924.  
  925.     /* Count words in cmdLine. */
  926.     wordCount = 0;
  927.     inWord = FALSE;
  928.     for (c = cmdLine; *c != '\0'; ++c) {
  929.     if (inWord) {
  930.         if (*c == ' ' || *c == '\t') 
  931.         inWord = FALSE;
  932.     }
  933.     else {
  934.         if (*c != ' ' && *c != '\t') {
  935.         inWord = TRUE;
  936.         ++wordCount;
  937.         }
  938.         }
  939.     }
  940.     
  941.     ++wordCount;                /* One for program name. */
  942.     argv = (char **) MemAlloc (sizeof (char _far *) * wordCount);
  943.     *pargv = argv;
  944.     *pargc = wordCount;
  945.  
  946.     modPath = (char *) MemAlloc (CMD_PATH_LEN);
  947.     mpLen = GetModuleFileName (hInstance, modPath, CMD_PATH_LEN);
  948.     if (mpLen > 0) {
  949.     *(modPath + mpLen) = '\0';
  950.         *(argv++) = modPath;
  951.     }
  952.     else {
  953.     MemFree (modPath);
  954.     *(argv++) = "Pine/Pico";
  955.     }
  956.     
  957.     /* Now break up command line. */
  958.     inWord = FALSE;
  959.     for (c = cmdLine; *c != '\0'; ++c) {
  960.     if (inWord) {
  961.         if (*c == ' ' || *c == '\t') {
  962.         inWord = FALSE;
  963.         *c = '\0';
  964.         }
  965.     }
  966.     else {
  967.         if (*c != ' ' && *c != '\t') {
  968.         inWord = TRUE;
  969.         *(argv++) = c;
  970.         }
  971.         }
  972.     }
  973. }
  974.  
  975.  
  976.  
  977.  
  978. /*---------------------------------------------------------------------------
  979.  *  LRESULT FAR PASCAL __export PWndProc( HWND hWnd, UINT uMsg,
  980.  *                                 WPARAM wParam, LPARAM lParam )
  981.  *
  982.  *  Description:
  983.  *     This is the TTY Window Proc.  This handles ALL messages
  984.  *     to the tty window.
  985.  *
  986.  *  Parameters:
  987.  *     As documented for Window procedures.
  988.  *
  989. /*--------------------------------------------------------------------------*/
  990.  
  991. LRESULT FAR PASCAL __export 
  992. PWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  993. {
  994. #ifdef CDEBUG
  995.     if (mswin_debug > 12) {
  996.         fprintf (mswin_debugfile, "PWndProc::  uMsg = 0x%x\n", uMsg);
  997.     fflush (mswin_debugfile);
  998.     }
  999. #endif
  1000.     switch (uMsg) {
  1001.     case WM_CREATE:
  1002.      MyTimerSet ();
  1003.          return (CreateTTYInfo (hWnd));
  1004.  
  1005.     case WM_COMMAND: 
  1006.     switch ((WORD) wParam) {
  1007.  
  1008.         case IDM_OPT_SETFONT:
  1009.         SelectTTYFont (hWnd);
  1010.         break ;
  1011.         
  1012.     case IDM_OPT_FONTSAMEAS:
  1013.         PrintFontSameAs (hWnd);
  1014.         break;
  1015.         
  1016.     case IDM_OPT_TOOLBAR:
  1017.         TBToggle (hWnd);
  1018.         break;
  1019.         
  1020.     case IDM_OPT_TOOLBARPOS:
  1021.         TBPosToggle (hWnd);
  1022.         break;
  1023.         
  1024.     case IDM_OPT_USEDIALOGS: {
  1025.         PTTYINFO    pTTYInfo;
  1026.         
  1027.         gfUseDialogs = !gfUseDialogs;
  1028.         pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  1029.         if (pTTYInfo) 
  1030.         DidResize (pTTYInfo);
  1031.         break;
  1032.             }
  1033.  
  1034. #ifdef ACCELERATORS
  1035.     case IDM_OPT_USEACCEL:
  1036.         AccelCtl (hWnd, ACCEL_TOGGLE, TRUE);
  1037.         break;
  1038. #endif        
  1039.         
  1040.     case IDM_OPT_SETPRINTFONT:
  1041.         PrintFontSelect (hWnd);
  1042.         break;
  1043.  
  1044.         case IDM_ABOUT:
  1045.             GoModalDialogBoxParam ( GET_HINST( hWnd ),
  1046.                                        MAKEINTRESOURCE( ABOUTDLGBOX ),
  1047.                                        hWnd,
  1048.                                        AboutDlgProc, (LPARAM) 0 ) ;
  1049.             break;
  1050.     
  1051.     case IDM_EDIT_CUT:
  1052.         EditCut ();
  1053.         break;
  1054.         
  1055.     case IDM_EDIT_COPY:
  1056.         EditCopy ();
  1057.         break;
  1058.         
  1059.     case IDM_EDIT_COPY_APPEND:
  1060.         EditCopyAppend ();
  1061.         break;
  1062.         
  1063.     case IDM_EDIT_PASTE:
  1064.         EditPaste ();
  1065.         break;
  1066.         
  1067.     case IDM_EDIT_CANCEL_PASTE:
  1068.         EditCancelPaste ();
  1069.         break;
  1070.         
  1071.     case IDM_HELP:
  1072.         ShowHelp ();
  1073.         break;
  1074.         
  1075.         
  1076. #if 0    /* No exit menu item. */
  1077.         case IDM_EXIT:
  1078.             PostMessage( hWnd, WM_CLOSE, NULL, 0L ) ;
  1079.             break;
  1080. #endif
  1081.     default:
  1082.         /* value falling within the menu item range are handled here. */
  1083.         if (wParam >= KS_RANGESTART && wParam <= KS_RANGEEND){
  1084.         ProcessMenuItem (hWnd, wParam);
  1085.         break;
  1086.         }
  1087.         break;
  1088.         }
  1089.     break ;
  1090.     
  1091.     case WM_VSCROLL:
  1092. #ifdef    WIN32
  1093.     ScrollTTY (hWnd, LOWORD(wParam), HIWORD(wParam), (HWND) lParam);
  1094. #else
  1095.     ScrollTTY (hWnd, wParam, LOWORD (lParam), (HWND) HIWORD (lParam));
  1096. #endif
  1097.     break;
  1098.  
  1099.     case WM_ERASEBKGND:
  1100.     if (IsIconic (hWnd)) 
  1101.         return (DefWindowProc (hWnd, WM_ICONERASEBKGND, wParam, lParam));
  1102.     else
  1103.         EraseTTY (hWnd, (HDC) wParam);
  1104.     break;
  1105.     
  1106.     case WM_QUERYDRAGICON:
  1107.     return ((DWORD)ghNormalIcon);
  1108.  
  1109.     case WM_PAINT:
  1110.     PaintTTY (hWnd);
  1111.         break ;
  1112.      
  1113.     case WM_GETMINMAXINFO:
  1114.     GetMinMaxInfoTTY (hWnd, (MINMAXINFO __far *)lParam);
  1115.     break;
  1116.  
  1117.     case WM_SIZE:
  1118.     SizeTTY (hWnd, wParam, HIWORD(lParam), LOWORD(lParam));
  1119.         break ;
  1120.     
  1121.     case WM_MOVE:
  1122.     MoveTTY (hWnd, (int) LOWORD(lParam), (int) HIWORD(lParam));
  1123.     break;
  1124.     
  1125.     case WM_WINDOWPOSCHANGING:
  1126.     /* Allows us to adjust new size of window. */
  1127.     AboutToSizeTTY (hWnd, (WINDOWPOS FAR *) lParam);
  1128.     break;
  1129.          
  1130.  
  1131.     /*
  1132.      * WM_KEYDOWN is sent for every "key press" and reports on they
  1133.      * keyboard key, with out processing shift and control keys.
  1134.      * WM_CHAR is a synthetic event, created from KEYDOWN and KEYUP
  1135.      * events.  It includes processing or control and shift characters.
  1136.      * But does not get generated for extended keys suchs as arrow
  1137.      * keys. 
  1138.      * I'm going to try to use KEYDOWN for processing just extended keys
  1139.      * and let CHAR handle the the rest.
  1140.      *
  1141.      * The only key combo that is special is ^-space.  For that, I'll use
  1142.      * WM_KEYDOWN and WM_KEYUP to track the state of the control key.
  1143.      */
  1144.     case WM_CHAR:
  1145.         ProcessTTYCharacter (hWnd, LOBYTE (wParam), (DWORD)lParam);
  1146.         break ;
  1147.      
  1148.     case WM_KEYDOWN:
  1149.     if (ProcessTTYKeyDown (hWnd, LOBYTE (wParam), (DWORD)lParam))
  1150.         return (0);
  1151.         return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
  1152.  
  1153.     case WM_KEYUP:
  1154.     if (ProcessTTYKeyUp (hWnd, LOBYTE (wParam), (DWORD)lParam))
  1155.         return (0);
  1156.         return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
  1157.     
  1158.     
  1159.     case WM_SYSCHAR:
  1160.     if (LOBYTE (wParam) == VK_F10) {
  1161.         ProcessTTYCharacter (hWnd, LOBYTE (wParam), (DWORD)lParam);
  1162.         return (0);
  1163.         }
  1164.         return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
  1165.         
  1166.     case WM_SYSKEYDOWN:
  1167.     if (LOBYTE (wParam) == VK_F10) 
  1168.         if (ProcessTTYKeyDown (hWnd, LOBYTE (wParam), (DWORD)lParam))
  1169.         return (0);
  1170.         return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
  1171.  
  1172.     case WM_SYSKEYUP:
  1173.     if (LOBYTE (wParam) == VK_F10) 
  1174.         if (ProcessTTYKeyUp (hWnd, LOBYTE (wParam), (DWORD)lParam))
  1175.         return (0);
  1176.         return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
  1177.     
  1178.  
  1179.     case WM_LBUTTONDOWN:
  1180.     ProcessTTYMouse (M_EVENT_DOWN, M_BUTTON_LEFT, LOWORD (lParam), 
  1181.              HIWORD (lParam), wParam);
  1182.     break;
  1183.  
  1184.     case WM_LBUTTONUP:
  1185.     if (ProcessTTYMouse (M_EVENT_UP, M_BUTTON_LEFT, LOWORD (lParam),
  1186.              HIWORD (lParam), wParam))
  1187.         goto callDef;
  1188.     break;
  1189.  
  1190.     case WM_MBUTTONDOWN:
  1191.     ProcessTTYMouse (M_EVENT_DOWN, M_BUTTON_MIDDLE, LOWORD (lParam), 
  1192.          HIWORD (lParam), wParam);
  1193.     break;
  1194.  
  1195.     case WM_MBUTTONUP:
  1196.     ProcessTTYMouse (M_EVENT_UP, M_BUTTON_MIDDLE, LOWORD (lParam), 
  1197.              HIWORD (lParam), wParam);
  1198.     break;
  1199.  
  1200.     case WM_RBUTTONDOWN:
  1201.     ProcessTTYMouse (M_EVENT_DOWN, M_BUTTON_RIGHT, LOWORD (lParam), 
  1202.              HIWORD (lParam), wParam);
  1203.     break;
  1204.  
  1205.     case WM_RBUTTONUP:
  1206.     ProcessTTYMouse (M_EVENT_UP, M_BUTTON_RIGHT, LOWORD (lParam), 
  1207.              HIWORD (lParam), wParam);
  1208.     break;
  1209.     
  1210.     case WM_MOUSEMOVE:
  1211.     ProcessTTYMouse (M_EVENT_TRACK, 0, LOWORD (lParam), 
  1212.             HIWORD (lParam), wParam);
  1213.     break;
  1214.  
  1215.  
  1216.     case WM_SETFOCUS:
  1217.         SetTTYFocus (hWnd);
  1218.         break;
  1219.  
  1220.     case WM_KILLFOCUS:
  1221.         KillTTYFocus (hWnd);
  1222.         break;
  1223.     
  1224.     case WM_SETCURSOR:
  1225.     /* Set cursor.  If in client, leave as is.  Otherwise, pass to 
  1226.      * DefWindow Proc */
  1227.     if (LOWORD(lParam) == HTCLIENT) {
  1228.         SetCursor (ghCursorCurrent);
  1229.         return (TRUE);
  1230.         }
  1231.         return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
  1232.  
  1233.     case WM_INITMENU:
  1234.     UpdateMenu (hWnd);
  1235.     break;
  1236.     
  1237.     case WM_TIMER:
  1238.     /* Really just used so that we continue to receive messages even while
  1239.      * in background.  Causes mswin_getc() to process message and return
  1240.      * to caller so that it can get some periodic processing in. */
  1241.     ProcessTimer ();
  1242.     break;
  1243.     
  1244.     case WM_QUERYENDSESSION:
  1245.     /* Returns non-zero if I can exit, otherwize zero, and the end
  1246.      * session operation stops. */
  1247.     return ((LRESULT)ConfirmExit ());
  1248.     
  1249.     case WM_ENDSESSION:
  1250.     /* Sent with wParam == TRUE when windows session is ending.
  1251.      * (wParam == FALSE means session is not ending). */
  1252.     if (wParam == TRUE) 
  1253.         ProcessOnExit ();
  1254.     break;
  1255.  
  1256.     case WM_DESTROY:
  1257.     KillTimer (hWnd, MY_TIMER_ID);
  1258.     DestroyTTYInfo (hWnd);
  1259.     PostQuitMessage (0);
  1260.     break;
  1261.  
  1262.  
  1263.     case WM_DROPFILES:
  1264.        if(ProcessTTYFileDrop((HANDLE) wParam))
  1265.      return(0);
  1266.  
  1267.        break;
  1268.  
  1269.  
  1270.     case WM_CLOSE:
  1271.     /* If the quit menu is active then insert the quit command
  1272.      * Otherwise, abort. */
  1273.     if (gpTTYInfo->menuItems[KS_EXIT - KS_RANGESTART].miActive) {
  1274.         CQAdd (gpTTYInfo->menuItems[KS_EXIT - KS_RANGESTART].miKey, 0);
  1275.     }
  1276.     else if (gSignalHUP != SIG_DFL && gSignalHUP != SIG_IGN) {
  1277.         if (MessageBox (hWnd, 
  1278.           "Abort PINE/PICO, possibly losing current work?",
  1279.           gszAppName, MB_OKCANCEL | MB_ICONQUESTION) == IDOK) 
  1280.         HUPDeliver ();
  1281.     }
  1282.     break;        
  1283.  
  1284.  
  1285.     default:
  1286. callDef:       
  1287.         return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
  1288.     }
  1289.     return 0L ;
  1290.  
  1291. } // end of PWndProc()
  1292.  
  1293.  
  1294.  
  1295.  
  1296. /*---------------------------------------------------------------------------
  1297.  *  LRESULT NEAR CreateTTYInfo( HWND hWnd )
  1298.  *
  1299.  *  Description:
  1300.  *     Creates the tty information structure and sets
  1301.  *     menu option availability.  Returns -1 if unsuccessful.
  1302.  *
  1303.  *  Parameters:
  1304.  *     HWND  hWnd
  1305.  *        Handle to main window.
  1306.  *
  1307.  *-------------------------------------------------------------------------*/
  1308.  
  1309. LOCAL LRESULT NEAR 
  1310. CreateTTYInfo (HWND hWnd)
  1311. {
  1312.     HMENU        hMenu;
  1313.     PTTYINFO        pTTYInfo;
  1314.     LOGFONT        newFont;
  1315.     int            i;
  1316.     
  1317. #ifdef SDEBUG
  1318.     if (mswin_debug >= 5) 
  1319.     fprintf (mswin_debugfile, "CreateTTYInfo:::  entered\n");
  1320. #endif
  1321.  
  1322.     pTTYInfo = (PTTYINFO) MemAlloc (sizeof (TTYINFO));
  1323.     if (pTTYInfo == NULL)
  1324.     return ((LRESULT) - 1);
  1325.     gpTTYInfo = pTTYInfo;
  1326.  
  1327.     /* initialize TTY info structure */
  1328.     memset (pTTYInfo, 0, sizeof (TTYINFO));
  1329.     pTTYInfo->wCursorState        = CS_SHOW;/* Shown but not focused. */
  1330.     pTTYInfo->scrollRange        = 0;
  1331.     pTTYInfo->scrollPos            = 0;
  1332.     pTTYInfo->scrollTo            = 0;
  1333.     pTTYInfo->scrollScale        = 0.0;
  1334.     pTTYInfo->fMinimized        = FALSE;
  1335.     pTTYInfo->fFocused            = FALSE;
  1336.     pTTYInfo->fNewLine            = FALSE;
  1337.     pTTYInfo->fMassiveUpdate        = FALSE;
  1338.     pTTYInfo->fNewMailIcon        = FALSE;
  1339.     pTTYInfo->autoWrap            = WRAP_NO_SCROLL;
  1340.     pTTYInfo->writeAccumCount        = 0;
  1341.     pTTYInfo->actNRow            = 0;
  1342.     pTTYInfo->actNColumn        = 0;
  1343.     pTTYInfo->xSize            = 0;
  1344.     pTTYInfo->ySize            = 0;
  1345.     pTTYInfo->xScroll            = 0;
  1346.     pTTYInfo->yScroll            = 0;
  1347.     pTTYInfo->xOffset            = MARGINE_LEFT;
  1348.     pTTYInfo->yOffset            = MARGINE_TOP;
  1349.     pTTYInfo->nColumn            = 0;
  1350.     pTTYInfo->nRow            = 0;
  1351.     pTTYInfo->xChar            = 0;
  1352.     pTTYInfo->yChar            = 0;
  1353.     pTTYInfo->fDesiredSize        = FALSE;
  1354.     pTTYInfo->hTTYFont            = NULL;
  1355.     pTTYInfo->rgbFGColor        = GetSysColor (COLOR_WINDOWTEXT);
  1356.     pTTYInfo->rgbBGColor        = GetSysColor (COLOR_WINDOW);
  1357.     pTTYInfo->rgbRFGColor        = GetSysColor (COLOR_HIGHLIGHTTEXT);
  1358.     pTTYInfo->rgbRBGColor        = GetSysColor (COLOR_HIGHLIGHT);
  1359.     pTTYInfo->hTBWnd            = NULL;
  1360.     pTTYInfo->toolBarSize        = 0;
  1361.     pTTYInfo->toolBarTop        = TRUE;
  1362.     pTTYInfo->curToolBarID        = IDD_TOOLBAR;
  1363.     pTTYInfo->hTBWnd            = NULL;
  1364.  
  1365.     /* Clear menu item array. */
  1366.     pTTYInfo->curWinMenu = PINEMENU;
  1367.     for (i = 0; i < KS_COUNT; ++i) 
  1368.     pTTYInfo->menuItems[i].miActive = FALSE;
  1369.     pTTYInfo->menuItemsCurrent = FALSE;
  1370.  
  1371.     /* Clear resize callback procs. */
  1372.     for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i) 
  1373.     pTTYInfo->resizer[i] = NULL;
  1374.  
  1375.  
  1376.     /* clear screen space */
  1377.     pTTYInfo->pScreen = NULL;
  1378.     pTTYInfo->pAttrib = NULL;
  1379.  
  1380.     /* setup default font information */
  1381.  
  1382.     newFont.lfHeight =         12;
  1383.     newFont.lfWidth =          0;
  1384.     newFont.lfEscapement =     0;
  1385.     newFont.lfOrientation =    0;
  1386.     newFont.lfWeight =         0;
  1387.     newFont.lfItalic =         0;
  1388.     newFont.lfUnderline =      0;
  1389.     newFont.lfStrikeOut =      0;
  1390.     newFont.lfCharSet =        OEM_CHARSET;
  1391.     newFont.lfOutPrecision =   OUT_DEFAULT_PRECIS;
  1392.     newFont.lfClipPrecision =  CLIP_DEFAULT_PRECIS;
  1393.     newFont.lfQuality =        DEFAULT_QUALITY;
  1394.     newFont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
  1395.     newFont.lfFaceName[0] =    '\0';
  1396.  
  1397.     /* set TTYInfo handle before any further message processing. */
  1398.  
  1399.     SetWindowLong (hWnd, GWL_PTTYINFO, (LPARAM) pTTYInfo);
  1400.  
  1401.     /* reset the character information, etc. */
  1402.  
  1403.     ResetTTYFont (hWnd, pTTYInfo, &newFont);
  1404.     
  1405.  
  1406.  
  1407.     hMenu = GetMenu (hWnd);
  1408.     EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND | MF_GRAYED);
  1409.     EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND | MF_GRAYED);
  1410.     EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND, MF_BYCOMMAND | MF_GRAYED);
  1411.     EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND | MF_GRAYED);
  1412.     return ((LRESULT) TRUE);
  1413. }
  1414.  
  1415.  
  1416.  
  1417. /*---------------------------------------------------------------------------
  1418.  *  BOOL NEAR DestroyTTYInfo( HWND hWnd )
  1419.  *
  1420.  *  Description:
  1421.  *     Destroys block associated with TTY window handle.
  1422.  *
  1423.  *  Parameters:
  1424.  *     HWND hWnd
  1425.  *        handle to TTY window
  1426.  *
  1427.  *-------------------------------------------------------------------------*/
  1428.  
  1429. LOCAL BOOL NEAR 
  1430. DestroyTTYInfo (HWND hWnd)
  1431. {
  1432.     PTTYINFO            pTTYInfo;
  1433.  
  1434.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  1435.     if (pTTYInfo == NULL)
  1436.     return (FALSE);
  1437.  
  1438.  
  1439.     DeleteObject (pTTYInfo->hTTYFont);
  1440.  
  1441.     MemFree (pTTYInfo);
  1442.     return (TRUE);
  1443. }
  1444.  
  1445.  
  1446.  
  1447. /*---------------------------------------------------------------------------
  1448.  *  void  ResizeTTYScreen( HWND hWnd, PTTYINFO pTTYInfo, 
  1449.  *                    int newNrow, int newNColumn);
  1450.  *
  1451.  *  Description:
  1452.  *        Resize the screen to new size, copying data.
  1453.  *
  1454.  *  Parameters:
  1455.  *     PTTYINFO  pTTYInfo
  1456.  *        pointer to TTY info structure
  1457.  *        newNCo.umn, newNRow
  1458.  *            new size of screen.
  1459.  *
  1460. /*--------------------------------------------------------------------------*/
  1461.  
  1462. LOCAL BOOL
  1463. ResizeTTYScreen (HWND hWnd, PTTYINFO pTTYInfo, int newNRow, int newNColumn)
  1464. {
  1465.     BYTE        *    pNewAttrib;
  1466.     CHAR        *    pNewScreen;
  1467.     void        *    source;
  1468.     void        *    dest;
  1469.     size_t            len;
  1470.     int                cells;
  1471.     int                r;
  1472.     extern TERM            term;
  1473.  
  1474.     
  1475.     if (newNColumn < MINNCOLUMN)
  1476.         newNColumn = MINNCOLUMN;
  1477.     if (newNRow < MINNROW)
  1478.         newNRow = MINNROW;
  1479.  
  1480. #ifdef SDEBUG
  1481.     if (mswin_debug >= 5) 
  1482.     fprintf (mswin_debugfile, "ResizeTTYScreen:::  entered, new row %d, col %d\n",
  1483.         newNRow, newNColumn);
  1484. #endif
  1485.     
  1486.     
  1487.     SelClear ();
  1488.     cells = newNColumn * newNRow;
  1489.     pNewScreen = (CHAR *)MemAlloc (cells * sizeof (CHAR));
  1490.     if (pNewScreen == NULL)
  1491.     return (FALSE);
  1492.     pNewAttrib = (CharAttrib *)MemAlloc (cells * sizeof (CharAttrib));
  1493.     if (pNewAttrib == NULL) {
  1494.     MemFree ((void *)pNewScreen);
  1495.     return (FALSE);
  1496.     }
  1497.  
  1498.  
  1499.     /* 
  1500.      * Clear new screen. 
  1501.      */
  1502.  
  1503.     assert (sizeof (CHAR) == 1);
  1504.     assert (sizeof (CharAttrib) == 1);
  1505.     memset ((void *)pNewScreen, ' ', cells);
  1506.     memset ((void *)pNewAttrib, 0, cells);
  1507.  
  1508.  
  1509.     /* 
  1510.      * Copy old screen onto new screen. 
  1511.      */
  1512.     if (pTTYInfo->pScreen != NULL) {
  1513.  
  1514.     for (r = 1; r <= newNRow && r <= pTTYInfo->actNRow; ++r) {
  1515.  
  1516.         
  1517.         source = pTTYInfo->pScreen + ((pTTYInfo->actNRow - r) * 
  1518.                             pTTYInfo->actNColumn);
  1519.         dest = pNewScreen + ((newNRow - r) * newNColumn);
  1520.         len = MIN (newNColumn, pTTYInfo->actNColumn) * sizeof (CHAR);
  1521.         memcpy (dest, source, len);
  1522.  
  1523.         
  1524.         source = pTTYInfo->pAttrib + ((pTTYInfo->actNRow - r) * 
  1525.                             pTTYInfo->actNColumn);
  1526.         dest = pNewAttrib + ((newNRow - r) * newNColumn);
  1527.         len = MIN (newNColumn, pTTYInfo->actNColumn) * sizeof(CharAttrib);
  1528.         memcpy (dest, source, len);
  1529.  
  1530.     }
  1531.     pTTYInfo->nColumn = MIN (pTTYInfo->nColumn, newNColumn);
  1532.     pTTYInfo->nRow = MAX (0, 
  1533.             pTTYInfo->nRow + (newNRow - pTTYInfo->actNRow));
  1534.     MemFree (pTTYInfo->pScreen);
  1535.     MemFree (pTTYInfo->pAttrib);
  1536.     }
  1537.     else {
  1538.     pTTYInfo->nColumn = MIN (pTTYInfo->nColumn, newNColumn);
  1539.     pTTYInfo->nRow = MIN (pTTYInfo->nRow, newNRow);
  1540.     }
  1541.     pTTYInfo->pScreen = pNewScreen;
  1542.     pTTYInfo->pAttrib = pNewAttrib;
  1543.     pTTYInfo->actNColumn = newNColumn;
  1544.     pTTYInfo->actNRow = newNRow;
  1545.     
  1546.     
  1547.     /* Repaint whole screen. */
  1548.     pTTYInfo->screenDirty = TRUE;
  1549.     pTTYInfo->eraseScreen = TRUE;
  1550.     InvalidateRect (hWnd, NULL, FALSE);
  1551.  
  1552.     
  1553.     
  1554.     /* Pico specific. */
  1555.     if (term.t_nrow == 0) {
  1556.     term.t_nrow = newNRow - 1;
  1557.     term.t_ncol = newNColumn;
  1558.     }
  1559.     
  1560.  
  1561.     return (TRUE);
  1562. }
  1563.         
  1564.         
  1565.  
  1566.  
  1567.  
  1568.  
  1569. /*---------------------------------------------------------------------------
  1570.  *  BOOL  ResetTTYFont( HWND hWnd, PTTYINFO pTTYInfo, LOGFONT *newFont)
  1571.  *
  1572.  *  Description:
  1573.  *     Resets the TTY character information and causes the
  1574.  *     screen to resize to update the scroll information.
  1575.  *
  1576.  *  Parameters:
  1577.  *     PTTYINFO  pTTYInfo
  1578.  *        pointer to TTY info structure
  1579.  *
  1580. /*--------------------------------------------------------------------------*/
  1581.  
  1582. LOCAL BOOL  
  1583. ResetTTYFont (HWND hWnd, PTTYINFO pTTYInfo, LOGFONT *newFont)
  1584. {
  1585.     HDC            hDC;
  1586.     HFONT        hFont;
  1587.     TEXTMETRIC        tm;
  1588.     int            newNRow;
  1589.     int            newNColumn;
  1590.     BOOL        newsize;
  1591.     int            i;
  1592. /*    RECT        rcWindow;*/
  1593.  
  1594.  
  1595. #ifdef SDEBUG
  1596.     if (mswin_debug >= 5) 
  1597.     fprintf (mswin_debugfile, "ResetTTYFont:::  entered, curent window size X %d, Y %d\n",
  1598.         pTTYInfo->xSize, pTTYInfo->ySize);
  1599. #endif
  1600.  
  1601.  
  1602.     if (NULL == pTTYInfo)
  1603.         return (FALSE);
  1604.     
  1605.     SelClear ();
  1606.  
  1607.     /*
  1608.      * Create new font.
  1609.      */
  1610.     hFont = CreateFontIndirect (newFont);
  1611.     if (hFont == NULL)
  1612.         return (FALSE);
  1613.     hDC = GetDC (hWnd);
  1614.     SelectObject (hDC, hFont);
  1615.     GetTextMetrics (hDC, &tm);
  1616.     ReleaseDC (hWnd, hDC);
  1617.  
  1618.     
  1619.     /*
  1620.      * Replace old font.
  1621.      */
  1622.     if (NULL != pTTYInfo->hTTYFont)
  1623.         DeleteObject (pTTYInfo->hTTYFont);
  1624.     pTTYInfo->hTTYFont = hFont;
  1625.     memcpy (&pTTYInfo->lfTTYFont, newFont, sizeof (LOGFONT));
  1626.  
  1627.     
  1628.     /* Update the char cell size. */
  1629.     pTTYInfo->xChar = tm.tmAveCharWidth;
  1630.     pTTYInfo->yChar = tm.tmHeight + tm.tmExternalLeading;
  1631.  
  1632.     /* Update the current number of rows and cols.  Don't allow
  1633.      * either to be less than zero. */
  1634.     newNRow = MAX (MINNROW, 
  1635.         MIN (MAXNROW, 
  1636.         (pTTYInfo->ySize - pTTYInfo->toolBarSize - (2 * MARGINE_TOP))/
  1637.                 pTTYInfo->yChar));
  1638.     newNColumn = MAX (MINNCOLUMN, 
  1639.         MIN (MAXNCOLUMN, (pTTYInfo->xSize - (2 * pTTYInfo->xOffset))/
  1640.                     pTTYInfo->xChar));
  1641.  
  1642.     newsize = newNRow != pTTYInfo->actNRow || 
  1643.             newNColumn != pTTYInfo->actNColumn;
  1644.     if (newsize)
  1645.         ResizeTTYScreen (hWnd, pTTYInfo, newNRow, newNColumn);
  1646.  
  1647.     /* Resize the carrot as well. */
  1648.     if (pTTYInfo->wCursorState == CS_VISIBLE) {
  1649.         HideCaret (hWnd);
  1650.         DestroyCaret();
  1651.         CreateCaret (hWnd, NULL, pTTYInfo->xChar, pTTYInfo->yChar);
  1652.         SetCaretPos ((pTTYInfo->nColumn * pTTYInfo->xChar) + pTTYInfo->xOffset,
  1653.             (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset);
  1654.         ShowCaret (hWnd);
  1655.     }
  1656.  
  1657.     /* Redraw screen and, if the "size" changed, tell the upper layers. */
  1658.     pTTYInfo->screenDirty = TRUE;
  1659.     pTTYInfo->eraseScreen = TRUE;
  1660.     InvalidateRect (hWnd, NULL, FALSE);
  1661.  
  1662.     /* Always call the resize functions - even if the screen size
  1663.      * has not changed, the font style may have. */
  1664.     DidResize (pTTYInfo);
  1665.  
  1666.     return (TRUE);
  1667. }
  1668.  
  1669.  
  1670.  
  1671. /*---------------------------------------------------------------------------
  1672.  *  BOOL  EraseTTY (HWND hWnd, HDC hDC)
  1673.  *
  1674.  *  Description:
  1675.  *     Erase the tty background.
  1676.  *     
  1677.  *
  1678.  *  Parameters:
  1679.  *     HWND hWnd
  1680.  *        handle to TTY window (as always)
  1681.  *
  1682. /*--------------------------------------------------------------------------*/
  1683.  
  1684. LOCAL BOOL
  1685. EraseTTY (HWND hWnd, HDC hDC)
  1686. {
  1687.     RECT    erect;
  1688.     HBRUSH    hBrush;
  1689.     
  1690.  
  1691.     GetClientRect (hWnd, &erect);
  1692.     hBrush = CreateSolidBrush (gpTTYInfo->rgbBGColor);
  1693.     if (hBrush != NULL) {
  1694.     FillRect (hDC, &erect, hBrush);
  1695.     DeleteObject (hBrush);
  1696.     }
  1697.     return (TRUE);
  1698. }
  1699.  
  1700.  
  1701.  
  1702.  
  1703. /*---------------------------------------------------------------------------
  1704.  *  BOOL  PaintTTY( HWND hWnd )
  1705.  *
  1706.  *  Description:
  1707.  *     Paints the rectangle determined by the paint struct of
  1708.  *     the DC.
  1709.  *
  1710.  *  Parameters:
  1711.  *     HWND hWnd
  1712.  *        handle to TTY window (as always)
  1713.  *
  1714. /*--------------------------------------------------------------------------*/
  1715.  
  1716. LOCAL BOOL
  1717. PaintTTY (HWND hWnd) 
  1718. {
  1719.     int          nRow, nCol;        /* Top right corner of update. */
  1720.     int         nEndRow, nEndCol;    /* lower right corner of update. */
  1721.     int         nCount;        /* Number of columns in each row. */
  1722.     int         nHorzPos, nVertPos;    /* Position of each text write. */
  1723.     int         col;            /* start col of run of similar attr */
  1724.     int         count;            /* count of run of similar attrib. */
  1725.     int         endCount;        /* How far to count. */
  1726.     CharAttrib    *pAttrib;
  1727.     HDC          hDC;
  1728.     HFONT        hOldFont;
  1729.     PTTYINFO    pTTYInfo;
  1730.     PAINTSTRUCT  ps;
  1731.     RECT         rect;
  1732.     RECT     erect;
  1733.     HBRUSH     hBrush;
  1734.     long     offset;        /* Offset into screen and attrib */
  1735.     CharAttrib     lastAttrib;        /* Attributes of last text write. */
  1736.     CharAttrib     newAttrib;        /* Attributes of this text write. */
  1737.  
  1738.  
  1739. #ifdef CDEBUG
  1740.     if (mswin_debug >= 9) 
  1741.     fprintf (mswin_debugfile, "PaintTTY:::  entered\n");
  1742. #endif
  1743.     
  1744.     
  1745.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  1746.     if (pTTYInfo == NULL)
  1747.     return (FALSE);
  1748.  
  1749.     if (IsIconic (hWnd)) {
  1750.     int pmm;
  1751.  
  1752.     hDC = BeginPaint (hWnd, &ps);
  1753.     pmm = SetMapMode (hDC, MM_TEXT);
  1754.     if (pTTYInfo->fNewMailIcon && ghNewMailIcon != NULL) 
  1755.         DrawIcon (hDC, 0, 0, ghNewMailIcon);
  1756.     else
  1757.         DrawIcon (hDC, 0, 0, ghNormalIcon);
  1758.     SetMapMode (hDC, pmm);
  1759.     EndPaint (hWnd, &ps);
  1760.     return (TRUE);
  1761.     }
  1762.         
  1763.  
  1764.     hDC = BeginPaint (hWnd, &ps);
  1765.     rect = ps.rcPaint;
  1766.     
  1767.     
  1768.     
  1769.     hOldFont = SelectObject (hDC, pTTYInfo->hTTYFont);
  1770.     SetTextColor (hDC, pTTYInfo->rgbFGColor);
  1771.     SetBkColor (hDC, pTTYInfo->rgbBGColor);
  1772.     SetBkMode (hDC, OPAQUE);
  1773.  
  1774. #if 0    
  1775.     nRow = min (pTTYInfo->actNRow - 1,
  1776.        max (0, (rect.top - pTTYInfo->yOffset) / pTTYInfo->yChar));
  1777. #endif
  1778.     nRow = (rect.top - pTTYInfo->yOffset) / pTTYInfo->yChar;
  1779.     CONSTRAIN (nRow, 0, pTTYInfo->actNRow - 1);
  1780.  
  1781.     nEndRow = min (pTTYInfo->actNRow - 1,
  1782.         ((rect.bottom - pTTYInfo->yOffset - 1) / pTTYInfo->yChar));
  1783.     nCol = min (pTTYInfo->actNColumn - 1,
  1784.         max (0, (rect.left - pTTYInfo->xOffset) / pTTYInfo->xChar));
  1785.     nEndCol = min (pTTYInfo->actNColumn - 1,
  1786.         ((rect.right - pTTYInfo->xOffset - 1) / pTTYInfo->xChar));
  1787.  
  1788.     nCount = nEndCol - nCol + 1;
  1789.     lastAttrib = CHAR_ATTR_NOT;
  1790.     
  1791.     
  1792.     /* Erase screen if necessary. */
  1793.     if (pTTYInfo->eraseScreen) {
  1794.     erect.top = 0;
  1795.     erect.left = 0;
  1796.     erect.bottom = pTTYInfo->ySize;
  1797.     erect.right = pTTYInfo->xSize;
  1798.     hBrush = CreateSolidBrush (pTTYInfo->rgbBGColor);
  1799.     if (hBrush != NULL) {
  1800.         FillRect (hDC, &erect, hBrush);
  1801.         DeleteObject (hBrush);
  1802.     }
  1803.     pTTYInfo->eraseScreen = FALSE;
  1804.     }
  1805. #if 0
  1806.     else {
  1807.     /* If not erasing entire screen, erase just the rect to be painted. */
  1808.     hBrush = CreateSolidBrush (pTTYInfo->rgbBGColor);
  1809.     if (hBrush != NULL) {
  1810.         FillRect (hDC, &rect, hBrush);
  1811.         DeleteObject (hBrush);
  1812.     }
  1813.     pTTYInfo->eraseScreen = FALSE;
  1814.     }
  1815. #endif
  1816.  
  1817.  
  1818.     /* Paint an inset frame around the text region. */
  1819.     if (gUse3DFrame) {
  1820.     /* Draw a inset 3d frame around the text area. */
  1821.     if (pTTYInfo->toolBarSize == 0) {
  1822.         erect.top = 0;
  1823.         erect.bottom = pTTYInfo->ySize;
  1824.     }
  1825.     else if (pTTYInfo->toolBarTop) {
  1826.         erect.top = pTTYInfo->toolBarSize;
  1827.         erect.bottom = pTTYInfo->ySize;
  1828.         }
  1829.         else {
  1830.         erect.top = 0;
  1831.         erect.bottom = pTTYInfo->ySize - pTTYInfo->toolBarSize;
  1832.         }
  1833.     erect.left = 0;
  1834.     erect.right = pTTYInfo->xSize;
  1835.     FrameRect3D (hDC, &erect, FRAME_3D_SIZE, FALSE);
  1836.     }
  1837.     else {
  1838.     /* Draw a thin line separator between the tool bar and the
  1839.      * text area. */
  1840.     if (pTTYInfo->toolBarSize > 0) {
  1841.  
  1842.         nHorzPos = (pTTYInfo->toolBarTop ? pTTYInfo->toolBarSize :
  1843.                 pTTYInfo->ySize - pTTYInfo->toolBarSize - 1);
  1844. #ifdef    WIN32
  1845.         MoveToEx (hDC, 0, nHorzPos, NULL);
  1846. #else
  1847.         MoveTo (hDC, 0, nHorzPos);
  1848. #endif
  1849.         LineTo (hDC, pTTYInfo->xSize, nHorzPos);
  1850.     }
  1851.     }
  1852.     
  1853.  
  1854.     
  1855.     
  1856.     
  1857.     /* Paint rows of text. */
  1858.     for (; nRow <= nEndRow; nRow++)    {
  1859.     nVertPos = (nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
  1860.     rect.top = nVertPos;
  1861.     rect.bottom = nVertPos + pTTYInfo->yChar;
  1862.     
  1863.     /* Paint runs of similar attributes. */
  1864.     col = nCol;                /* Start at left. */
  1865.     while (col <= nEndCol) {        /* While not past right. */
  1866.  
  1867.         /* Starting with Character at nRow, col, what is its attribute? */
  1868.         offset = (nRow * pTTYInfo->actNColumn) + col;
  1869.         newAttrib = *(pTTYInfo->pAttrib + offset);
  1870.         
  1871.         if (newAttrib != lastAttrib) {
  1872.         /* Set new attributes.  If Reverse or Selected, then
  1873.          * show in reverse colors.  But if neither, or both, then
  1874.          * normal colors. */
  1875.         if (newAttrib > 0 && newAttrib 
  1876.             < (CHAR_ATTR_REV | CHAR_ATTR_SEL)) {
  1877.             SetTextColor (hDC, pTTYInfo->rgbRFGColor);
  1878.             SetBkColor (hDC, pTTYInfo->rgbRBGColor);
  1879.         }
  1880.         else {
  1881.             SetTextColor (hDC, pTTYInfo->rgbFGColor);
  1882.             SetBkColor (hDC, pTTYInfo->rgbBGColor);
  1883.         }
  1884.         }
  1885.         
  1886.         /* Find run of similar attributes. */
  1887.         count = 1;
  1888.         pAttrib = pTTYInfo->pAttrib + offset + 1;
  1889.         endCount = nEndCol - col;
  1890.         while (count <= endCount && *pAttrib++ == newAttrib) 
  1891.         ++count;
  1892.     
  1893.         /* Paint run of characters from nRow, col to nRow, col + count 
  1894.          * rect.top and rect.bottom have already been calculated. */
  1895.         nHorzPos = (col * pTTYInfo->xChar) + pTTYInfo->xOffset;
  1896.         rect.left = nHorzPos;
  1897.         rect.right = nHorzPos + pTTYInfo->xChar * count;
  1898.         ExtTextOut (hDC, nHorzPos, nVertPos, ETO_OPAQUE | ETO_CLIPPED, &rect,
  1899.         (LPSTR)(pTTYInfo->pScreen + offset),
  1900.         count, NULL);
  1901.     
  1902.         /* Move pointer to end of this span of characters. */
  1903.         col += count;
  1904.         lastAttrib = newAttrib;
  1905.         }
  1906.     }
  1907.  
  1908.     SelectObject (hDC, hOldFont);
  1909.     EndPaint (hWnd, &ps);
  1910.     MoveTTYCursor (hWnd);
  1911.     pTTYInfo->screenDirty = FALSE;
  1912.     return (TRUE);
  1913. }
  1914.  
  1915.  
  1916.  
  1917.  
  1918.  
  1919.  
  1920. /* FillRectColor
  1921.  *
  1922.  *
  1923.  * Description:
  1924.  *        FillRectColor is similar to PatB in toolbar.c
  1925.  *
  1926.  *        Code based on MFC source code, so presumably efficient.
  1927.  *
  1928.  */
  1929. LOCAL void
  1930. FillRectColor(HDC hDC, RECT * pRC, COLORREF color)
  1931. {
  1932.     SetBkColor(hDC, color);
  1933.     ExtTextOut(hDC, 0, 0, ETO_OPAQUE, pRC, NULL, 0, NULL);
  1934. }
  1935.  
  1936.  
  1937. /** FrameRect3D
  1938.  *
  1939.  *
  1940.  * Inputs:
  1941.  *        hdc            - HDC
  1942.  *        pRC            - pointer to rectangle
  1943.  *        width        - width for frame (usually one)
  1944.  *        raised        - TRUE for raised effect, FALSE for sunken effect
  1945.  *
  1946.  * Outputs:
  1947.  *        none
  1948.  *
  1949.  * Returns:
  1950.  *        void
  1951.  *
  1952.  * Description
  1953.  *        Draws a frame with a 3D effect.
  1954.  *
  1955.  *        If 'raised' is true, the rectangle will look raised (like
  1956.  *        a button); otherwise, the rectangle will look sunk.
  1957.  *
  1958.  */
  1959. void 
  1960. FrameRect3D(HDC hdc, RECT * pRC, int width, BOOL raised)
  1961. {
  1962.     COLORREF    hilite, shadow;
  1963.     RECT        rcTemp;
  1964.  
  1965.     shadow        = GetSysColor(COLOR_BTNSHADOW);
  1966.     hilite        = GetSysColor(COLOR_BTNHIGHLIGHT);
  1967.  
  1968.     rcTemp        = *pRC;
  1969.  
  1970.     rcTemp.right    = rcTemp.left + width;
  1971.     FillRectColor(hdc, &rcTemp, raised ? hilite : shadow);
  1972.     rcTemp.right    = pRC->right;
  1973.  
  1974.     rcTemp.bottom    = rcTemp.top + width;
  1975.     FillRectColor(hdc, &rcTemp, raised ? hilite : shadow);
  1976.     rcTemp.bottom    = pRC->bottom;
  1977.  
  1978.     rcTemp.left        = rcTemp.right - width;
  1979.     FillRectColor(hdc, &rcTemp, raised ? shadow : hilite);
  1980.     rcTemp.left        = pRC->left;
  1981.  
  1982.     rcTemp.top        = rcTemp.bottom - width;
  1983.     FillRectColor(hdc, &rcTemp, raised ? shadow : hilite);
  1984. }
  1985.  
  1986.  
  1987.  
  1988. /*---------------------------------------------------------------------------
  1989.  *  BOOL  GetMinMaxInfoTTY (HWND hWnd, (MINMAXINFO __far *)lParam)
  1990.  *
  1991.  *  Description:
  1992.  *     Return the min and max size that the window can be.
  1993.  *
  1994.  *  Parameters:
  1995.  *     HWND hWnd
  1996.  *        handle to TTY window
  1997.  *
  1998.  *     MINMAXINFO
  1999.  *      Info structure that Windows would like us to fill.
  2000.  *
  2001. /*--------------------------------------------------------------------------*/
  2002.  
  2003. LOCAL BOOL  
  2004. GetMinMaxInfoTTY (HWND hWnd, MINMAXINFO __far *lpmmi)
  2005. {
  2006.     PTTYINFO        pTTYInfo;
  2007.     
  2008.     
  2009. #ifdef SDEBUG
  2010.     if (mswin_debug >= 5) 
  2011.     fprintf (mswin_debugfile, "GetMinMaxInfoTTY:::  entered\n");
  2012. #endif
  2013.     
  2014.     
  2015.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  2016.     if (pTTYInfo == NULL)
  2017.     return (FALSE);
  2018.  
  2019.     lpmmi->ptMaxTrackSize.x = lpmmi->ptMaxSize.x = MIN (lpmmi->ptMaxSize.x,
  2020.                 pTTYInfo->xChar * MAXNCOLUMN + WIN_X_BORDER_SIZE);
  2021.     lpmmi->ptMaxTrackSize.y = lpmmi->ptMaxSize.y = MIN (lpmmi->ptMaxSize.y, 
  2022.                 pTTYInfo->yChar * MAXNROW + WIN_Y_BORDER_SIZE);
  2023.  
  2024.     lpmmi->ptMinTrackSize.x = MAX (WIN_MIN_X_SIZE, 
  2025.             pTTYInfo->xChar * MINNCOLUMN + WIN_X_BORDER_SIZE);
  2026.     lpmmi->ptMinTrackSize.y = MAX (WIN_MIN_Y_SIZE,
  2027.             pTTYInfo->yChar * MINNROW + WIN_Y_BORDER_SIZE);
  2028.     return (TRUE);
  2029. }
  2030.  
  2031.  
  2032.  
  2033. /*---------------------------------------------------------------------------
  2034.  *  BOOL  AboutToSizeTTY (HWND hWnd, WINDOWPOS *winPos)
  2035.  *
  2036.  *  Description:
  2037.  *      Called just before Windows resizes our window.  We can change the
  2038.  *    values in 'winPos' to change the new size of the window.
  2039.  *
  2040.  *    If mswin_setwindow() was called when the window was minimized we
  2041.  *    set the new size here.
  2042.  *
  2043.  *  Parameters:
  2044.  *     HWND hWnd
  2045.  *        handle to TTY window
  2046.  *
  2047.  *     WORD wVertSize
  2048.  *        new vertical size
  2049.  *
  2050.  *     WORD wHorzSize
  2051.  *        new horizontal size
  2052.  *
  2053. /*--------------------------------------------------------------------------*/
  2054. LOCAL BOOL  
  2055. AboutToSizeTTY (HWND hWnd, WINDOWPOS *winPos)
  2056. {
  2057.     PTTYINFO    pTTYInfo;
  2058.  
  2059.     
  2060.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  2061.     if (pTTYInfo == NULL)
  2062.         return ( FALSE );
  2063.  
  2064. #ifdef SDEBUG
  2065.     if (mswin_debug >= 5) 
  2066.     fprintf (mswin_debugfile, "AboutToSizeTTY:::  After x%lx, pos %d, %d, size %d, %d, flags x%x\n", 
  2067.         winPos->hwndInsertAfter, winPos->x, winPos->y, winPos->cx,
  2068.         winPos->cy, winPos->flags);
  2069.  
  2070. #endif
  2071.  
  2072.     /*
  2073.      * Was the window minimized AND is there a desired new size for it?
  2074.      * AND is this a call that specifies a new size and position.
  2075.      */
  2076.     if (pTTYInfo->fMinimized && pTTYInfo->fDesiredSize &&
  2077.         (winPos->flags & (SWP_NOSIZE | SWP_NOMOVE)) == 0) {
  2078. #ifdef SDEBUG
  2079.     if (mswin_debug >= 5) 
  2080.         fprintf (mswin_debugfile, "AboutToSizeTTY:::  substitue pos (%d, %d), size (%d, %d)\n",
  2081.             pTTYInfo->xDesPos, pTTYInfo->yDesPos,
  2082.             pTTYInfo->xDesSize, pTTYInfo->yDesSize);
  2083. #endif
  2084.     pTTYInfo->fDesiredSize = FALSE;
  2085.     winPos->x = pTTYInfo->xDesPos;
  2086.     winPos->y = pTTYInfo->yDesPos;
  2087.     winPos->cx = pTTYInfo->xDesSize;
  2088.     winPos->cy = pTTYInfo->yDesSize;
  2089.     }
  2090.     return (TRUE);
  2091. }
  2092.  
  2093.  
  2094. /*---------------------------------------------------------------------------
  2095.  *  BOOL  SizeTTY( HWND hWnd, int fwSizeType, CORD wVertSize, 
  2096.  *                    CORD wHorzSize)
  2097.  *
  2098.  *  Description:
  2099.  *     Sizes TTY and sets up scrolling regions.
  2100.  *
  2101.  *  Parameters:
  2102.  *     HWND hWnd
  2103.  *        handle to TTY window
  2104.  *
  2105.  *     WORD wVertSize
  2106.  *        new vertical size
  2107.  *
  2108.  *     WORD wHorzSize
  2109.  *        new horizontal size
  2110.  *
  2111. /*--------------------------------------------------------------------------*/
  2112.  
  2113. LOCAL BOOL  
  2114. SizeTTY (HWND hWnd, int fwSizeType, CORD wVertSize, CORD wHorzSize)
  2115. {
  2116. /*  int        nScrollAmt ;*/
  2117.     PTTYINFO    pTTYInfo;
  2118.     int        newNColumn;
  2119.     int        newNRow;
  2120.     int        i;
  2121.  
  2122.  
  2123. #ifdef SDEBUG
  2124.     if (mswin_debug >= 5) 
  2125.     fprintf (mswin_debugfile, "SizeTTY:::  entered, sizeType %d, New screen size %d, %d pixels\n",
  2126.         fwSizeType, wHorzSize, wVertSize);
  2127. #endif
  2128.  
  2129.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  2130.     if (pTTYInfo == NULL)
  2131.         return ( FALSE );
  2132.  
  2133.     
  2134.     /*
  2135.      * Is the window being minimized?
  2136.      */
  2137.     pTTYInfo->fNewMailIcon = FALSE;
  2138.     if (fwSizeType == SIZE_MINIMIZED) {
  2139.     pTTYInfo->fMinimized = TRUE;
  2140.     return (TRUE);
  2141.     }
  2142.     
  2143.     pTTYInfo->fMinimized = FALSE;
  2144.         
  2145.         
  2146.     pTTYInfo->ySize = (int) wVertSize;
  2147.     newNRow = max (MINNROW, min (MAXNROW, 
  2148.         (pTTYInfo->ySize - pTTYInfo->toolBarSize - (2 * MARGINE_TOP)) / 
  2149.                     pTTYInfo->yChar));
  2150.     if (pTTYInfo->toolBarTop)            
  2151.     pTTYInfo->yOffset = MARGINE_TOP + pTTYInfo->toolBarSize;
  2152.     else
  2153.     pTTYInfo->yOffset = MARGINE_TOP;
  2154.         
  2155.  
  2156.     pTTYInfo->xSize = (int) wHorzSize;
  2157.     newNColumn = max (MINNCOLUMN, 
  2158.             min (MAXNCOLUMN, (pTTYInfo->xSize - (2 * MARGINE_LEFT)) / 
  2159.             pTTYInfo->xChar));
  2160.     pTTYInfo->xOffset = MARGINE_LEFT;
  2161.  
  2162.  
  2163.     ResizeTTYScreen (hWnd, pTTYInfo, newNRow, newNColumn);
  2164.     pTTYInfo->screenDirty = TRUE;
  2165.     pTTYInfo->eraseScreen = TRUE;
  2166.     InvalidateRect (hWnd, NULL, FALSE);
  2167.  
  2168.     if (pTTYInfo->hTBWnd) {
  2169.     if (pTTYInfo->toolBarTop) 
  2170.         /* Position at top of window. */
  2171.         SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP, 
  2172.             0, 0, 
  2173.             wHorzSize, pTTYInfo->toolBarSize, 
  2174.             SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
  2175.     else
  2176.         /* Position at bottom of window. */
  2177.         SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP, 
  2178.             0, pTTYInfo->ySize - pTTYInfo->toolBarSize, 
  2179.             wHorzSize, pTTYInfo->toolBarSize, 
  2180.             SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
  2181.     }
  2182.  
  2183.  
  2184.     DidResize (pTTYInfo);
  2185.  
  2186.     return (TRUE);
  2187. }
  2188.  
  2189.  
  2190.  
  2191. /*---------------------------------------------------------------------------
  2192.  *  BOOL  MoveTTY (HWND hWnd, int xPos, int yPos)
  2193.  *
  2194.  *  Description:
  2195.  *     Notes the fact that the window has moved. 
  2196.  *     Only real purpose is so we can tell pine which can the write the
  2197.  *     new window position to the 'pinerc' file.
  2198.  *
  2199.  *  Parameters:
  2200.  *     HWND hWnd
  2201.  *        handle to TTY window
  2202.  *
  2203.  *     int xPos, yPos
  2204.  *      New position of the top left corner. 
  2205.  *
  2206.  *
  2207. /*--------------------------------------------------------------------------*/
  2208.  
  2209. LOCAL BOOL  
  2210. MoveTTY (HWND hWnd, int xPos, int yPos)
  2211. {
  2212.     int        i;
  2213.     
  2214. #ifdef SDEBUG
  2215.     if (mswin_debug >= 5) 
  2216.     fprintf (mswin_debugfile, "MoveTTY:::  entered\n");
  2217. #endif
  2218.  
  2219.     DidResize (gpTTYInfo);
  2220.     return (TRUE);
  2221. }
  2222.  
  2223.  
  2224.  
  2225. /*---------------------------------------------------------------------------
  2226.  *  void  ScrollTTY ()
  2227.  *
  2228.  *  Description:
  2229.  *      Respond to a scroll message by either calling the scroll
  2230.  *      callback or inserting a scroll character into the input
  2231.  *      stream.
  2232.  *
  2233.  *    Scrolling in the TTY window is complicated by the way pine
  2234.  *      process events.  Normal windows applications are entirly event
  2235.  *      driven.  The top level does nothing but dispatch events.  In
  2236.  *      pine, the top level implements the logic.  Events are only
  2237.  *      dispatched by the lowest levels.
  2238.  *
  2239.  *    In normal applications, mouse down in the scroll bar causes
  2240.  *    an internal scroll function to be entered.  It tracks the
  2241.  *    mouse and issues scroll messages as needed.  If the
  2242.  *    application redraws the screen the scroll function also
  2243.  *    dispatches the WM_PAINT message to the application.  The
  2244.  *    important thing is that this internal scroll function does
  2245.  *    not exit until the mouse is released.
  2246.  *
  2247.  *    We implement two methods for pine's screen managers to deal
  2248.  *    with scroll events.  They can receive scroll events as
  2249.  *    characters in the normal input stream or they can register a
  2250.  *    callback function.
  2251.  *
  2252.  *    In the "insert a character in the queue" mode, the scroll
  2253.  *    event never gets process until the mouse is release.  Auto
  2254.  *    repeat scroll events (generated as the mouse is held down)
  2255.  *    will cause multiple chars to be inserted in the queue, none
  2256.  *    of which will get processed till the mouse is release.  In a
  2257.  *    compromise, we allow only one scroll char in the queue,
  2258.  *    which prevents makes for a more friendly and controllable
  2259.  *    behavior.
  2260.  *
  2261.  *    In the callback mode, the callback repaints the screen, and
  2262.  *    then it calls mswin_flush() which PROCESSES EVENTS!  The
  2263.  *    Windows internal scroll function does NOT expect that.  This
  2264.  *    behavior can confuses the scroll function, causing it to
  2265.  *    miss mouse up events.  We avoid this by setting gScrolling TRUE
  2266.  *    when this routine is entered and FALSE when this routine exits
  2267.  *    All PeekMessage processors avoid processing any message when 
  2268.  *    gScrolling is TRUE.
  2269.  *
  2270. /*--------------------------------------------------------------------------*/
  2271.  
  2272. LOCAL void
  2273. ScrollTTY (HWND hWnd, int wScrollCode, int nPos, HWND hScroll)
  2274. {    
  2275.     PTTYINFO    pTTYInfo;
  2276.     POINT    pos;
  2277.     WORD    cmd;
  2278.     long    scroll_pos;
  2279.     int        hitCode;
  2280.     BOOL    noAction = FALSE;
  2281.     BOOL    didScroll;
  2282.     FARPROC    prevBlockingProc;
  2283.         
  2284.  
  2285.     
  2286.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  2287.  
  2288.     if (pTTYInfo == NULL || gScrolling)
  2289.     return;
  2290.  
  2291.     gScrolling = TRUE;
  2292.     if (gWSBlockingProc != NULL) 
  2293.     prevBlockingProc = WSASetBlockingHook (gWSBlockingProc);
  2294.     
  2295.     
  2296.     
  2297.     
  2298.     switch (wScrollCode) {
  2299.     case SB_BOTTOM:
  2300.     cmd = MSWIN_KEY_SCROLLTO;
  2301.     scroll_pos = pTTYInfo->scrollTo = 0;
  2302.     break;
  2303.     
  2304.     case SB_TOP:
  2305.     cmd = MSWIN_KEY_SCROLLTO;
  2306.     scroll_pos = pTTYInfo->scrollTo = pTTYInfo->scrollRange;
  2307.     break;
  2308.     
  2309.     case SB_LINEDOWN:
  2310.     cmd = MSWIN_KEY_SCROLLDOWNLINE;
  2311.     scroll_pos = 1;
  2312.         break;
  2313.  
  2314.     case SB_LINEUP:
  2315.     cmd = MSWIN_KEY_SCROLLUPLINE;
  2316.     scroll_pos = 1;
  2317.         break;
  2318.  
  2319.     case SB_PAGEDOWN:
  2320.     cmd = MSWIN_KEY_SCROLLDOWNPAGE;
  2321.     scroll_pos = 1;
  2322.         break;
  2323.  
  2324.     case SB_PAGEUP:
  2325.     cmd = MSWIN_KEY_SCROLLUPPAGE;
  2326.     scroll_pos = 1;
  2327.         break;
  2328.     
  2329.     case SB_THUMBTRACK:
  2330.     case SB_THUMBPOSITION:
  2331.     cmd = MSWIN_KEY_SCROLLTO;
  2332.     scroll_pos = pTTYInfo->scrollTo = 
  2333.                 (long) ((float)nPos * pTTYInfo->scrollScale);
  2334.     break;
  2335.  
  2336.     default:
  2337.     noAction = TRUE;
  2338.     break;
  2339.     }
  2340.  
  2341.     
  2342.     /*
  2343.      * If there is a scroll callback call that.  If there is no scroll 
  2344.      * callback or the callback says it did not handle the event (returned,
  2345.      * FALSE) queue the scroll cmd.
  2346.      */
  2347.     if (!noAction) {
  2348.     SelClear ();
  2349.     didScroll = FALSE;
  2350.     if (gScrollCallback != NULL) {
  2351.         /* Call scrolling callback.  Set blocking hook to our routine
  2352.          * which prevents messages from being dispatched. */
  2353.         if (gWSBlockingProc != NULL) 
  2354.         WSASetBlockingHook (gWSBlockingProc);
  2355.         didScroll = gScrollCallback (cmd, scroll_pos);
  2356.         if (gWSBlockingProc != NULL) 
  2357.         WSAUnhookBlockingHook ();
  2358.         }
  2359.     /*
  2360.      * If no callback or callback did not do the scrolling operation,
  2361.      * insert a scroll cmd in the input stream.
  2362.      */
  2363.     if (!didScroll)
  2364.         CQAddUniq (cmd, 0);
  2365.     }
  2366.  
  2367.  
  2368.     gScrolling = FALSE;
  2369.     return;
  2370. }
  2371.  
  2372.  
  2373.  
  2374. /*
  2375.  * This routine is inserted as the winsock blocking hook.  It's main perpos
  2376.  * is to NOT dispatch messages.
  2377.  */
  2378. /*BOOL CALLBACK __export  --  MSC 7.0 choked */
  2379. BOOL CALLBACK
  2380. NoMsgsAreSent (void)
  2381. {
  2382.     return (FALSE);
  2383. }
  2384.  
  2385.  
  2386.  
  2387. /*---------------------------------------------------------------------------
  2388.  *  BOOL  SetTTYFocus( HWND hWnd )
  2389.  *
  2390.  *  Description:
  2391.  *     Sets the focus to the TTY window also creates caret.
  2392.  *
  2393.  *  Parameters:
  2394.  *     HWND hWnd
  2395.  *        handle to TTY window
  2396.  *
  2397. /*--------------------------------------------------------------------------*/
  2398.  
  2399. LOCAL BOOL  
  2400. SetTTYFocus (HWND hWnd)
  2401. {
  2402.     PTTYINFO  pTTYInfo;
  2403.  
  2404. #ifdef SDEBUG
  2405.     if (mswin_debug >= 5) 
  2406.     fprintf (mswin_debugfile, "SetTTYFocus:::  entered\n");
  2407. #endif
  2408.  
  2409.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  2410.     if (pTTYInfo == NULL)
  2411.         return (FALSE);
  2412.  
  2413.     pTTYInfo->fFocused = TRUE;
  2414.     pTTYInfo->wCursorState |= CS_FOCUSED;
  2415.     gKeyControlDown = FALSE;
  2416.  
  2417.     if (pTTYInfo->wCursorState == CS_VISIBLE) {
  2418.         CreateCaret (hWnd, NULL, pTTYInfo->xChar, pTTYInfo->yChar);
  2419.         ShowCaret (hWnd);
  2420.     }
  2421.  
  2422.     MoveTTYCursor (hWnd);
  2423.     return (TRUE);
  2424. }
  2425.  
  2426.  
  2427.  
  2428.  
  2429. /*---------------------------------------------------------------------------
  2430.  *  BOOL  KillTTYFocus( HWND hWnd )
  2431.  *
  2432.  *  Description:
  2433.  *     Kills TTY focus and destroys the caret.
  2434.  *
  2435.  *  Parameters:
  2436.  *     HWND hWnd
  2437.  *        handle to TTY window
  2438.  *
  2439. /*--------------------------------------------------------------------------*/
  2440.  
  2441. LOCAL BOOL  
  2442. KillTTYFocus (HWND hWnd)
  2443. {
  2444.     PTTYINFO  pTTYInfo;
  2445.  
  2446. #ifdef SDEBUG
  2447.     if (mswin_debug >= 5) 
  2448.     fprintf (mswin_debugfile, "KillTTYFocus:::  entered\n");
  2449. #endif
  2450.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  2451.     if (pTTYInfo == NULL)
  2452.         return (FALSE);
  2453.  
  2454.     if (pTTYInfo->wCursorState == CS_VISIBLE) {
  2455.         HideCaret (hWnd);
  2456.         DestroyCaret();
  2457.     }
  2458.  
  2459.     pTTYInfo->wCursorState &= ~CS_FOCUSED;
  2460.     pTTYInfo->fFocused = FALSE;
  2461.     gKeyControlDown = FALSE;
  2462.  
  2463.     return (TRUE);
  2464. }
  2465.  
  2466.  
  2467.  
  2468.  
  2469. /*---------------------------------------------------------------------------
  2470.  *  BOOL  MoveTTYCursor( HWND hWnd )
  2471.  *
  2472.  *  Description:
  2473.  *     Moves caret to current position.
  2474.  *
  2475.  *  Parameters:
  2476.  *     HWND hWnd
  2477.  *        handle to TTY window
  2478.  *
  2479. /*--------------------------------------------------------------------------*/
  2480.  
  2481. LOCAL BOOL  
  2482. MoveTTYCursor (HWND hWnd)
  2483. {
  2484.     PTTYINFO  pTTYInfo;
  2485.  
  2486.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  2487.     if (pTTYInfo == NULL)
  2488.         return (FALSE);
  2489.  
  2490.     if (pTTYInfo->wCursorState == CS_VISIBLE && 
  2491.         !pTTYInfo->fMassiveUpdate) {
  2492.     HideCaret (hWnd);
  2493.     SetCaretPos ((pTTYInfo->nColumn * pTTYInfo->xChar) + pTTYInfo->xOffset,
  2494.         (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset);
  2495.     ShowCaret (hWnd);
  2496.     }
  2497.  
  2498.     return (TRUE);
  2499. }
  2500.  
  2501.  
  2502.  
  2503.  
  2504. /*---------------------------------------------------------------------------
  2505.  *  BOOL  ProcessTTYKeyDown ( HWND hWnd, WORD bOut, DWORD keyData )
  2506.  *
  2507.  *  Description:
  2508.  *    Called to process MW_KEYDOWN message.  We are only interested in 
  2509.  *    virtual keys that pico/pine use.  All others get passed on to 
  2510.  *    the default message handler.  Regular key presses will return 
  2511.  *    latter as a WM_CHAR message, with SHIFT and CONTROL processing
  2512.  *    already done.
  2513.  *
  2514.  *    We do watch for VK_CONTROL to keep track of it's state such
  2515.  *    that we can implement ^_space.
  2516.  *
  2517.  *  Parameters:
  2518.  *     HWND hWnd
  2519.  *        handle to TTY window
  2520.  *
  2521.  *     BYTE key
  2522.  *      Virtual key code.
  2523.  *
  2524.  *     DWORD keyData
  2525.  *      Additional flags passed in lParam for WM_KEYDOWN
  2526.  *
  2527. /*--------------------------------------------------------------------------*/
  2528.  
  2529. LOCAL BOOL  
  2530. ProcessTTYKeyDown (HWND hWnd, WORD key, DWORD keyData)
  2531. {
  2532.     WORD        myKey;
  2533.     
  2534.     
  2535.     /* Special keys. */
  2536.     if (keyData & 0X20000000)
  2537.     return (FALSE);            /* Message NOT handled. */
  2538.  
  2539.     switch (key) {
  2540.     case VK_UP:        myKey = MSWIN_KEY_UP;        break;
  2541.     case VK_DOWN:        myKey = MSWIN_KEY_DOWN;        break;
  2542.     case VK_RIGHT:        myKey = MSWIN_KEY_RIGHT;    break;
  2543.     case VK_LEFT:        myKey = MSWIN_KEY_LEFT;        break;
  2544.     case VK_PRIOR:        myKey = MSWIN_KEY_PREVPAGE;    break;
  2545.     case VK_NEXT:        myKey = MSWIN_KEY_NEXTPAGE;    break;
  2546.     case VK_HOME:        myKey = MSWIN_KEY_HOME;        break;
  2547.     case VK_END:        myKey = MSWIN_KEY_END;        break;
  2548.     case VK_DELETE:        myKey = MSWIN_KEY_DELETE;    break;
  2549.     case VK_F1:        myKey = MSWIN_KEY_F1;        break;
  2550.     case VK_F2:        myKey = MSWIN_KEY_F2;        break;
  2551.     case VK_F3:        myKey = MSWIN_KEY_F3;        break;
  2552.     case VK_F4:        myKey = MSWIN_KEY_F4;        break;
  2553.     case VK_F5:        myKey = MSWIN_KEY_F5;        break;
  2554.     case VK_F6:        myKey = MSWIN_KEY_F6;        break;
  2555.     case VK_F7:        myKey = MSWIN_KEY_F7;        break;
  2556.     case VK_F8:        myKey = MSWIN_KEY_F8;        break;
  2557.     case VK_F9:        myKey = MSWIN_KEY_F9;        break;
  2558.     case VK_F10:        myKey = MSWIN_KEY_F10;        break;
  2559.     case VK_F11:        myKey = MSWIN_KEY_F11;        break;
  2560.     case VK_F12:        myKey = MSWIN_KEY_F12;        break;
  2561.     
  2562.     /* Control is special - I keep track, but do not claim to handle. */
  2563.     case VK_CONTROL:    gKeyControlDown = TRUE;
  2564.                 return (FALSE);
  2565.                 
  2566.     case '6':
  2567.         /* Ctrl-^ is used to set and clear the mark in the composer (pico)
  2568.          * On most other systems Ctrl-6 does the same thing.  Allow that
  2569.          * on windows too... */
  2570.         if (gKeyControlDown) 
  2571.         myKey = 0x1e;
  2572.         else
  2573.         return (FALSE);
  2574.         break;
  2575.                 
  2576.     default:        return (FALSE);    /* Message NOT handled.*/
  2577.     }
  2578.  
  2579.     CQAdd (myKey, 0);
  2580.     return (TRUE);            /* Message handled .*/
  2581. }
  2582.  
  2583.  
  2584.  
  2585. /*---------------------------------------------------------------------------
  2586.  *  BOOL  ProcessTTYKeyUp ( HWND hWnd, WORD bOut, DWORD keyData )
  2587.  *
  2588.  *  Description:
  2589.  *    Called to process MW_KEYDOWN message. 
  2590.  *    Used only to detect when the control key goes up.
  2591.  *
  2592.  *  Parameters:
  2593.  *     HWND hWnd
  2594.  *        handle to TTY window
  2595.  *
  2596.  *     BYTE key
  2597.  *      Virtual key code.
  2598.  *
  2599.  *     DWORD keyData
  2600.  *      Additional flags passed in lParam for WM_KEYDOWN
  2601.  *
  2602. /*--------------------------------------------------------------------------*/
  2603.  
  2604. LOCAL BOOL  
  2605. ProcessTTYKeyUp (HWND hWnd, WORD key, DWORD keyData)
  2606. {
  2607.     WORD        myKey;
  2608.     
  2609.     
  2610.     /* Special keys. */
  2611.     if (keyData & 0X20000000)
  2612.     return (FALSE);            /* Message NOT handled. */
  2613.  
  2614.     if (key == VK_CONTROL) 
  2615.     gKeyControlDown = FALSE;
  2616.                 
  2617.     return (FALSE);    /* Message NOT handled.*/
  2618. }
  2619.  
  2620.  
  2621.  
  2622.  
  2623. /*---------------------------------------------------------------------------
  2624.  *  BOOL  ProcessTTYCharacter( HWND hWnd, WORD bOut, DWORD keyData )
  2625.  *
  2626.  *  Description:
  2627.  *        Place the character into a queue.
  2628.  *
  2629.  *  Parameters:
  2630.  *     HWND hWnd
  2631.  *        handle to TTY window
  2632.  *
  2633.  *     BYTE bOut
  2634.  *        byte from keyboard
  2635.  *
  2636. /*--------------------------------------------------------------------------*/
  2637.  
  2638. LOCAL BOOL  
  2639. ProcessTTYCharacter (HWND hWnd, WORD bOut, DWORD keyData)
  2640. {
  2641.     if (bOut == ' ' && gKeyControlDown)
  2642.     bOut = '\0';
  2643.     CQAdd (bOut, keyData);
  2644.     return (TRUE);        /* Message handled. */
  2645. }
  2646.  
  2647.  
  2648.  
  2649.  
  2650.  
  2651. /*---------------------------------------------------------------------------
  2652.  *  BOOL  ProcessTTYMouse(int mevent, int button, int xPos, int yPos, 
  2653.  *                WPARAM keys)
  2654.  *
  2655.  *  Description:
  2656.  *    This is the central control for all mouse events.  Every event
  2657.  *    gets put into a queue to wait for the upper layer.  
  2658.  * 
  2659.  *    The upper's input routine calls checkmouse() which pulls the
  2660.  *    mouse event off the input queue.  checkmouse() has a list of
  2661.  *    of screen regions.  Some regions correspond to a "menu" item
  2662.  *    (text button at bottom of screen).  There is generally one
  2663.  *    region for the central region of the screen.
  2664.  *
  2665.  *    Because pine/pico do not interpret mouse drags, we do that here.
  2666.  *    When the user presses the button and drags the mouse across the
  2667.  *    screen this select the text in the region defined by the drag.
  2668.  *    The operation is local to mswin.c, and can only get what text
  2669.  *    is on the screen.
  2670.  *
  2671.  *    The one exception is that now pico interprets mouse drag events
  2672.  *    in the body.  pico signals that it wants to track the mouse
  2673.  *    by calling mswin_allowmousetrack().  This will 1) turn off
  2674.  *    our mouse tracking and 2) cause mouse movement events to 
  2675.  *    be put on the mouse queue.
  2676.  *
  2677.  *
  2678.  *  Parameters:
  2679.  *     HWND hWnd
  2680.  *        handle to TTY window
  2681.  *
  2682.  *     BYTE bOut
  2683.  *        byte from keyboard
  2684.  *
  2685. /*--------------------------------------------------------------------------*/
  2686.  
  2687. LOCAL BOOL  
  2688. ProcessTTYMouse (int mevent, int button, CORD xPos, CORD yPos, WPARAM winkeys)
  2689. {
  2690.     int        nRow;
  2691.     int        nColumn;
  2692.     int        keys;
  2693.  
  2694.     /* 
  2695.      * Convert to cell position.
  2696.      */
  2697.     nColumn = (xPos - gpTTYInfo->xOffset) / gpTTYInfo->xChar;
  2698.     if (xPos < gpTTYInfo->xOffset)
  2699.     --nColumn;
  2700.     nRow = (yPos - gpTTYInfo->yOffset) / gpTTYInfo->yChar;
  2701.     if (xPos < gpTTYInfo->yOffset)
  2702.     --nRow;
  2703. #if 0
  2704.     nColumn = max (0, nColumn);
  2705.     nColumn = min (gpTTYInfo->actNColumn-1, nColumn);
  2706.     nRow = max (0, nRow);
  2707.     nRow = min (gpTTYInfo->actNRow-1, nRow);
  2708. #endif
  2709.  
  2710.     /*
  2711.      * Convert window's keys. 
  2712.      */
  2713.     keys = 0;
  2714.     if (winkeys & MK_CONTROL)
  2715.         keys |= M_KEY_CONTROL;
  2716.     if (winkeys & MK_SHIFT)
  2717.         keys |= M_KEY_SHIFT;
  2718.  
  2719.     
  2720.     /* 
  2721.      * Tracking event or mouse up/down?
  2722.      */
  2723.     if (mevent != M_EVENT_TRACK) {
  2724.  
  2725.     /*
  2726.      * Tracking.  Only start tracking mouse down in the text region
  2727.      * But allow mouse up anywhere. 
  2728.      */
  2729.     if ( (nRow >= 0 && nRow < gpTTYInfo->actNRow &&
  2730.           nColumn >= 0 && nColumn < gpTTYInfo->actNColumn)
  2731.         || mevent == M_EVENT_UP) {
  2732.         /*
  2733.          * Insert event into queue.
  2734.          */
  2735.         MQAdd (mevent, button, nRow, nColumn, keys, 0);
  2736.  
  2737.  
  2738.         /*
  2739.          * Mouse tracking.  When the mouse goes down we start
  2740.          * capturing all mouse movement events.  If no one else wants
  2741.          * them we will start defining a text selection.
  2742.          */
  2743.         if (mevent == M_EVENT_DOWN) {
  2744.         gMouseTracking = TRUE;
  2745.         SetCapture (ghTTYWnd);
  2746.         if (!gAllowMouseTrack && button == M_BUTTON_LEFT)
  2747.             SelStart (nRow, nColumn);
  2748.         }
  2749.         else {
  2750.         ReleaseCapture ();
  2751.         if (!gAllowMouseTrack && button == M_BUTTON_LEFT)
  2752.             SelFinish (nRow, nColumn);
  2753.         gMouseTracking = FALSE;
  2754.         }
  2755.         }
  2756.     }
  2757.     else {
  2758.     /*
  2759.      * Who is doing the tracking?
  2760.      */
  2761.     if (gAllowMouseTrack) {
  2762.         /* For tracking, Button info is different. */
  2763.         if (keys & MK_LBUTTON) 
  2764.         button = M_BUTTON_LEFT;
  2765.         else if (keys & MK_MBUTTON) 
  2766.         button = M_BUTTON_MIDDLE;
  2767.         else if (keys & MK_RBUTTON) 
  2768.         button = M_BUTTON_RIGHT;
  2769.         MQAdd (mevent, button, nRow, nColumn, keys, 
  2770.             MSWIN_MF_REPLACING);
  2771.         }
  2772.     else 
  2773.         SelTrackMouse (nRow, nColumn);
  2774.     }
  2775.  
  2776.     return (0);        /* Message handled. */
  2777. }
  2778.  
  2779.  
  2780.  
  2781.  
  2782. /*---------------------------------------------------------------------------
  2783.  *  BOOL  ProcessTimer ()
  2784.  *
  2785.  *  Description:
  2786.  *     Process the periodic timer calls.
  2787.  *     
  2788.  *
  2789.  *  Parameters:
  2790.  *    None.
  2791.  *
  2792. /*--------------------------------------------------------------------------*/
  2793. LOCAL void
  2794. ProcessTimer (void)
  2795. {
  2796.     /* Check the OnTaskList. */
  2797.     if (gOnTaskList != NULL)
  2798.     ProcessOnTask ();
  2799.  
  2800.     /* Time to deliver an alarm signal? */
  2801.     if (gAlarmTimeout != 0 && GetTickCount () / 1000 > gAlarmTimeout)
  2802.     AlarmDeliver ();
  2803.  
  2804.     /* Time to make the periodic callback. */
  2805.     if (gPeriodicCallback != NULL && 
  2806.         GetTickCount() / 1000 > gPeriodicCBTimeout) {
  2807.     gPeriodicCBTimeout = GetTickCount() / 1000 + 
  2808.                         gPeriodicCBTime;
  2809.     gPeriodicCallback ();
  2810.     }
  2811.     
  2812.     /* 
  2813.      * If tracking the mouse, insert a fake mouse tracking message
  2814.      * At the last know location of the mouse.
  2815.      */
  2816.     if (gAllowMouseTrack) {
  2817.     gMTEvent.event = M_EVENT_TRACK;
  2818.     MQAdd (gMTEvent.event, gMTEvent.button, gMTEvent.nRow, 
  2819.         gMTEvent.nColumn, gMTEvent.keys, MSWIN_MF_REPLACING);
  2820.     }
  2821. }
  2822.  
  2823.  
  2824. /*---------------------------------------------------------------------------
  2825.  *  BOOL  WriteTTYBlock( HWND hWnd, LPSTR lpBlock, int nLength )
  2826.  *
  2827.  *  Description:
  2828.  *     Writes block to TTY screen.  Nothing fancy - just
  2829.  *     straight TTY.
  2830.  *
  2831.  *  Parameters:
  2832.  *     HWND hWnd
  2833.  *        handle to TTY window
  2834.  *
  2835.  *     LPSTR lpBlock
  2836.  *        far pointer to block of data
  2837.  *
  2838.  *     int nLength
  2839.  *        length of block
  2840.  *
  2841. /*--------------------------------------------------------------------------*/
  2842.  
  2843. LOCAL BOOL  
  2844. WriteTTYBlock (HWND hWnd, LPSTR lpBlock, int nLength)
  2845. {
  2846.     int                i;
  2847.     PTTYINFO            pTTYInfo;
  2848.     RECT            rect;
  2849.     BOOL            fNewLine;
  2850.     long            offset;
  2851.  
  2852.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  2853.     if (pTTYInfo == NULL)
  2854.         return (FALSE);
  2855.  
  2856.     for (i = 0 ; i < nLength; i++) {
  2857.     switch (lpBlock[i]) {
  2858.     case ASCII_BEL:
  2859.         // Bell
  2860.         MessageBeep (0) ;
  2861.         break ;
  2862.  
  2863.     case ASCII_BS:
  2864.         // Backspace
  2865.         if (pTTYInfo->nColumn > 0)
  2866.             --pTTYInfo->nColumn;
  2867.         MoveTTYCursor (hWnd);
  2868.         break;
  2869.  
  2870.     case ASCII_CR:
  2871.         // Carriage return
  2872.         pTTYInfo->nColumn = 0 ;
  2873.         MoveTTYCursor (hWnd);
  2874.         if (!pTTYInfo->fNewLine)
  2875.             break;
  2876.  
  2877.         // fall through
  2878.  
  2879.     case ASCII_LF:
  2880.         // Line feed
  2881.         if (++pTTYInfo->nRow == pTTYInfo->actNRow) {
  2882.         /* Scroll the Screen. */
  2883.         memmove ((LPSTR)pTTYInfo->pScreen,
  2884.             (LPSTR) (pTTYInfo->pScreen + pTTYInfo->actNColumn),
  2885.             ((pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn) *
  2886.                 sizeof (CHAR));
  2887.         assert (sizeof (CHAR) == 1);
  2888.         memset ((LPSTR) (pTTYInfo->pScreen + 
  2889.                 (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn),
  2890.             ' ', pTTYInfo->actNColumn);
  2891.  
  2892.         /* Scroll the Attributes. */
  2893.         memmove ((LPSTR)pTTYInfo->pAttrib,
  2894.             (LPSTR) (pTTYInfo->pAttrib + pTTYInfo->actNColumn),
  2895.             ((pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn) *
  2896.                 sizeof (CharAttrib));
  2897.         assert (sizeof (CharAttrib) == 1);
  2898.         memset ((LPSTR) (pTTYInfo->pScreen + 
  2899.                 (pTTYInfo->actNRow - 1) * pTTYInfo->actNColumn),
  2900.             0, pTTYInfo->actNColumn);
  2901.  
  2902.  
  2903.         pTTYInfo->screenDirty = TRUE;
  2904.         pTTYInfo->eraseScreen = TRUE;
  2905.         InvalidateRect (hWnd, NULL, FALSE);
  2906.         --pTTYInfo->nRow;
  2907.         }
  2908.         MoveTTYCursor (hWnd);
  2909.         break;
  2910.  
  2911.  
  2912.  
  2913.     default:
  2914.         offset = (pTTYInfo->nRow * pTTYInfo->actNColumn) +
  2915.             pTTYInfo->nColumn;
  2916.         *(pTTYInfo->pScreen + offset) = lpBlock[i];
  2917.         *(pTTYInfo->pAttrib + offset) = pTTYInfo->curAttrib;
  2918.         rect.left = (pTTYInfo->nColumn * pTTYInfo->xChar) +
  2919.             pTTYInfo->xOffset;
  2920.         rect.right = rect.left + pTTYInfo->xChar;
  2921.         rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) +
  2922.             pTTYInfo->yOffset;
  2923.         rect.bottom = rect.top + pTTYInfo->yChar;
  2924.         pTTYInfo->screenDirty = TRUE;
  2925.         InvalidateRect (hWnd, &rect, FALSE);
  2926.  
  2927.         /* Line Wrap. */
  2928.         if (pTTYInfo->nColumn < pTTYInfo->actNColumn - 1)
  2929.             pTTYInfo->nColumn++ ;
  2930.         else if (pTTYInfo->autoWrap == WRAP_ON || 
  2931.             (pTTYInfo->autoWrap == WRAP_NO_SCROLL && 
  2932.                 pTTYInfo->nRow < pTTYInfo->actNRow - 1)) {
  2933.             fNewLine = pTTYInfo->fNewLine;
  2934.             pTTYInfo->fNewLine = FALSE;
  2935.             WriteTTYBlock (hWnd, "\r\n", 2);
  2936.             pTTYInfo->fNewLine = fNewLine;
  2937.         }
  2938.         break;
  2939.     }
  2940.     }
  2941.     return (TRUE);
  2942. }
  2943.  
  2944.  
  2945.  
  2946.  
  2947. /*---------------------------------------------------------------------------
  2948.  *  BOOL  WriteTTYText ( HWND hWnd, LPSTR lpBlock, int nLength )
  2949.  *
  2950.  *  Description:
  2951.  *    Like WriteTTYBlock but optimized for strings that are text only,
  2952.  *    no carrage control characters. 
  2953.  *
  2954.  *  Parameters:
  2955.  *     HWND hWnd
  2956.  *        handle to TTY window
  2957.  *
  2958.  *     LPSTR lpBlock
  2959.  *        far pointer to block of data
  2960.  *
  2961.  *     int nLength
  2962.  *        length of block
  2963.  *
  2964. /*--------------------------------------------------------------------------*/
  2965.  
  2966. LOCAL BOOL  
  2967. WriteTTYText (HWND hWnd, LPSTR lpText, int nLength)
  2968. {
  2969.     int                i;
  2970.     PTTYINFO            pTTYInfo;
  2971.     RECT            rect;
  2972.     BOOL            fNewLine;
  2973.     long            offset;
  2974.     long            colEnd;
  2975.     long            screenEnd;
  2976.     BOOL            wraper;
  2977.  
  2978.     
  2979.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  2980.     if (pTTYInfo == NULL)
  2981.         return ( FALSE );
  2982.  
  2983.     
  2984.     /* Calculate offset of cursor, end of current column, and end of screen */
  2985.     offset = (pTTYInfo->nRow * pTTYInfo->actNColumn) + pTTYInfo->nColumn;
  2986.     colEnd = (pTTYInfo->nRow + 1) * pTTYInfo->actNColumn;
  2987.     screenEnd = pTTYInfo->actNRow * pTTYInfo->actNColumn;
  2988.     
  2989.     
  2990.     /* Text is allowed to wrap around to subsequent lines, but not past end
  2991.      * of screen */
  2992.     if (offset + nLength > screenEnd)
  2993.     nLength = screenEnd - offset;
  2994.  
  2995.  
  2996.     /* Calculate bounding rectangle. */
  2997.     if (offset + nLength <= colEnd) {
  2998.     /* Single line. */
  2999.     rect.left = (pTTYInfo->nColumn * pTTYInfo->xChar) + pTTYInfo->xOffset;
  3000.     rect.right = rect.left + (pTTYInfo->xChar * nLength);
  3001.     rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
  3002.     rect.bottom = rect.top + pTTYInfo->yChar;
  3003.     }
  3004.     else {
  3005.     /* Wraps across multiple lines.  Calculate one rect to cover all 
  3006.      * lines. */
  3007.     rect.left = 0;
  3008.     rect.right = pTTYInfo->xSize;
  3009.     rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
  3010.     rect.bottom = ((((offset + nLength) / pTTYInfo->actNColumn) + 1) * 
  3011.             pTTYInfo->yChar) + pTTYInfo->yOffset;
  3012.     }
  3013.     
  3014.     
  3015.     /* Apply text and attributes to screen in one smooth motion. */
  3016.     memcpy (pTTYInfo->pScreen + offset, lpText, nLength);
  3017.     memset (pTTYInfo->pAttrib + offset, pTTYInfo->curAttrib, nLength);
  3018.     
  3019.     
  3020.     /* New cursor position. */
  3021.     offset += nLength;
  3022.     if (offset == screenEnd) {
  3023.     pTTYInfo->nRow = pTTYInfo->actNRow - 1;
  3024.     pTTYInfo->nColumn = pTTYInfo->actNColumn - 1;
  3025.     }
  3026.     else {
  3027.     pTTYInfo->nRow = offset / pTTYInfo->actNColumn;
  3028.     pTTYInfo->nColumn = offset % pTTYInfo->actNColumn;
  3029.     }
  3030.     
  3031.  
  3032.     /* Invalidate rectangle */
  3033.     pTTYInfo->screenDirty = TRUE;
  3034.     InvalidateRect (hWnd, &rect, FALSE);
  3035.     return (TRUE);
  3036. }
  3037.  
  3038.  
  3039. /*---------------------------------------------------------------------------
  3040.  *  BOOL  WriteTTYChar (HWND hWnd, char ch)
  3041.  *
  3042.  *  Description:
  3043.  *    Write a single character to the cursor position and advance the
  3044.  *    cursor.  Does not handle carage control.
  3045.  *
  3046.  *  Parameters:
  3047.  *     HWND hWnd
  3048.  *        handle to TTY window
  3049.  *
  3050.  *     char ch
  3051.  *      character being written.
  3052.  *
  3053. /*--------------------------------------------------------------------------*/
  3054.  
  3055. LOCAL BOOL  
  3056. WriteTTYChar (HWND hWnd, char ch)
  3057. {
  3058.     int                i;
  3059.     PTTYINFO            pTTYInfo;
  3060.     RECT            rect;
  3061.     BOOL            fNewLine;
  3062.     long            offset;
  3063.     long            colEnd;
  3064.     long            screenEnd;
  3065.  
  3066.     
  3067.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  3068.     if (pTTYInfo == NULL)
  3069.     return (FALSE);
  3070.  
  3071.     offset = (pTTYInfo->nRow * pTTYInfo->actNColumn) +
  3072.         pTTYInfo->nColumn;
  3073.     
  3074.     *(pTTYInfo->pScreen + offset) = ch;
  3075.     *(pTTYInfo->pAttrib + offset) = pTTYInfo->curAttrib;
  3076.  
  3077.     rect.left = (pTTYInfo->nColumn * pTTYInfo->xChar) + pTTYInfo->xOffset;
  3078.     rect.right = rect.left + pTTYInfo->xChar;
  3079.     rect.top = (pTTYInfo->nRow * pTTYInfo->yChar) + pTTYInfo->yOffset;
  3080.     rect.bottom = rect.top + pTTYInfo->yChar;
  3081.     pTTYInfo->screenDirty = TRUE;
  3082.     InvalidateRect (hWnd, &rect, FALSE);
  3083.     
  3084.     
  3085.  
  3086.     /* Line Wrap. */
  3087.     if (pTTYInfo->nColumn < pTTYInfo->actNColumn - 1)
  3088.     pTTYInfo->nColumn++ ;
  3089.     else if ((pTTYInfo->autoWrap == WRAP_ON || 
  3090.           pTTYInfo->autoWrap == WRAP_NO_SCROLL) && 
  3091.             pTTYInfo->nRow < pTTYInfo->actNRow - 1) {
  3092.        pTTYInfo->nRow++;
  3093.        pTTYInfo->nColumn = 0;
  3094.     }
  3095.     return (TRUE);
  3096. }
  3097.  
  3098. /*---------------------------------------------------------------------------
  3099.  *  VOID  GoModalDialogBoxParam( HINSTANCE hInstance,
  3100.  *                                   LPCSTR lpszTemplate, HWND hWnd,
  3101.  *                                   DLGPROC lpDlgProc, LPARAM lParam )
  3102.  *
  3103.  *  Description:
  3104.  *     It is a simple utility function that simply performs the
  3105.  *     MPI and invokes the dialog box with a DWORD paramter.
  3106.  *
  3107.  *  Parameters:
  3108.  *     similar to that of DialogBoxParam() with the exception
  3109.  *     that the lpDlgProc is not a procedure instance
  3110.  *
  3111. /*--------------------------------------------------------------------------*/
  3112.  
  3113. LOCAL VOID  
  3114. GoModalDialogBoxParam( HINSTANCE hInstance, LPCSTR lpszTemplate,
  3115.                                  HWND hWnd, DLGPROC lpDlgProc, LPARAM lParam )
  3116. {
  3117.    DLGPROC  lpProcInstance ;
  3118.  
  3119.    lpProcInstance = (DLGPROC) MakeProcInstance( (FARPROC) lpDlgProc,
  3120.                                                 hInstance ) ;
  3121.    DialogBoxParam( hInstance, lpszTemplate, hWnd, lpProcInstance, lParam ) ;
  3122.    FreeProcInstance( (FARPROC) lpProcInstance ) ;
  3123. }
  3124.  
  3125.  
  3126.  
  3127.  
  3128.  
  3129. /*---------------------------------------------------------------------------
  3130.  *  BOOL FAR PASCAL __export AboutDlgProc( HWND hDlg, UINT uMsg,
  3131.  *                                WPARAM wParam, LPARAM lParam )
  3132.  *
  3133.  *  Description:
  3134.  *     Simulates the Windows System Dialog Box.
  3135.  *
  3136.  *  Parameters:
  3137.  *     Same as standard dialog procedures.
  3138.  *
  3139. /*--------------------------------------------------------------------------*/
  3140.  
  3141. BOOL FAR PASCAL __export 
  3142. AboutDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3143. {
  3144.    switch (uMsg) {
  3145.       case WM_INITDIALOG:
  3146.       {
  3147.          int          idModeString ;
  3148.          char         szTemp [81];
  3149.          DWORD        dwFreeMemory, dwWinFlags ;
  3150.          WORD         wFreeResources, wRevision, wVersion ;
  3151.  
  3152. #ifdef ABOUTDLG_USEBITMAP
  3153.          // if we are using the bitmap, hide the icon
  3154.  
  3155.          ShowWindow( GetDlgItem( hDlg, IDD_ABOUTICON ), SW_HIDE ) ;
  3156. #endif
  3157.          // sets up the version number for Windows
  3158.  
  3159.          wVersion = LOWORD (GetVersion());
  3160.          switch (HIBYTE (wVersion)) {
  3161.             case 10:
  3162.                wRevision = 1;
  3163.                break;
  3164.  
  3165.             default:
  3166.                wRevision = 0;
  3167.                break;
  3168.          }
  3169.          wVersion &= 0xFF;
  3170.  
  3171.      
  3172.          /* sets up version number for PINE */
  3173.  
  3174.          GetDlgItemText (hDlg, IDD_VERSION, szTemp, sizeof (szTemp));
  3175.          wsprintf (TempBuf, szTemp, mswin_majorver(), mswin_minorver(),
  3176.            mswin_compilation_date());
  3177.          SetDlgItemText (hDlg, IDD_VERSION, (LPSTR) TempBuf);
  3178.  
  3179.          // get by-line
  3180.  
  3181.          LoadString (GET_HINST (hDlg), IDS_BYLINE, TempBuf,
  3182.                      sizeof (TempBuf));
  3183.          SetDlgItemText (hDlg, IDD_BYLINE, TempBuf);
  3184.  
  3185.       }
  3186.       return ( TRUE ) ;
  3187.  
  3188. #ifdef ABOUTDLG_USEBITMAP
  3189.       // used to paint the bitmap
  3190.  
  3191.       case WM_PAINT:
  3192.       {
  3193.          HBITMAP      hBitMap ;
  3194.          HDC          hDC, hMemDC ;
  3195.          PAINTSTRUCT  ps ;
  3196.  
  3197.          // load bitmap and display it
  3198.  
  3199.          hDC = BeginPaint( hDlg, &ps ) ;
  3200.          if (NULL != (hMemDC = CreateCompatibleDC( hDC )))
  3201.          {
  3202.             hBitMap = LoadBitmap( GET_HINST( hDlg ),
  3203.                                   MAKEINTRESOURCE( PINEBITMAP ) ) ;
  3204.             hBitMap = SelectObject( hMemDC, hBitMap ) ;
  3205.             BitBlt( hDC, 10, 10, 64, 64, hMemDC, 0, 0, SRCCOPY ) ;
  3206.             DeleteObject( SelectObject( hMemDC, hBitMap ) ) ;
  3207.             DeleteDC( hMemDC ) ;
  3208.          }
  3209.          EndPaint( hDlg, &ps ) ;
  3210.       }
  3211.       break ;
  3212. #endif
  3213.  
  3214.       case WM_COMMAND:
  3215.          if ((WORD) wParam == IDD_OK)
  3216.          {
  3217.             EndDialog( hDlg, TRUE ) ;
  3218.             return ( TRUE ) ;
  3219.          }
  3220.          break;
  3221.    }
  3222.    return ( FALSE ) ;
  3223.  
  3224. } // end of AboutDlgProc()
  3225.  
  3226.  
  3227.  
  3228.  
  3229.  
  3230.  
  3231.  
  3232.  
  3233.  
  3234. /*---------------------------------------------------------------------------
  3235.  *  BOOL  SelectTTYFont( HWND hDlg )
  3236.  *
  3237.  *  Description:
  3238.  *     Selects the current font for the TTY screen.
  3239.  *     Uses the Common Dialog ChooseFont() API.
  3240.  *
  3241.  *  Parameters:
  3242.  *     HWND hDlg
  3243.  *        handle to settings dialog
  3244.  *
  3245. /*--------------------------------------------------------------------------*/
  3246.  
  3247. BOOL  
  3248. LOCAL SelectTTYFont (HWND hWnd)
  3249. {
  3250.     CHOOSEFONT        cfTTYFont;
  3251.     LOGFONT        newFont;
  3252.     PTTYINFO        pTTYInfo;
  3253.  
  3254.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  3255.     if (pTTYInfo == NULL)
  3256.     return (FALSE);
  3257.  
  3258.     memcpy (&newFont, &gpTTYInfo->lfTTYFont, sizeof (LOGFONT));
  3259.  
  3260.     cfTTYFont.lStructSize    = sizeof (CHOOSEFONT);
  3261.     cfTTYFont.hwndOwner      = hWnd ;
  3262.     cfTTYFont.hDC            = NULL ;
  3263.     cfTTYFont.rgbColors      = pTTYInfo->rgbFGColor;
  3264.     cfTTYFont.lpLogFont      = &newFont;
  3265.     cfTTYFont.Flags          = CF_SCREENFONTS | CF_FIXEDPITCHONLY |
  3266.         CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_ANSIONLY | 
  3267.         CF_FORCEFONTEXIST | CF_LIMITSIZE;
  3268.     cfTTYFont.nSizeMin         = FONT_MIN_SIZE;
  3269.     cfTTYFont.nSizeMax         = FONT_MAX_SIZE;
  3270.     cfTTYFont.lCustData      = (long) 0 ;
  3271.     cfTTYFont.lpfnHook       = NULL ;
  3272.     cfTTYFont.lpTemplateName = NULL ;
  3273.     cfTTYFont.hInstance      = GET_HINST (hWnd);
  3274.  
  3275.  
  3276.  
  3277.     if (ChooseFont (&cfTTYFont)) {
  3278.     pTTYInfo->rgbFGColor = cfTTYFont.rgbColors;
  3279.     ResetTTYFont (hWnd, pTTYInfo, &newFont);
  3280.     }
  3281.  
  3282.     return (TRUE);
  3283. }
  3284.  
  3285.  
  3286.  
  3287. /*
  3288.  * Set a specific color (forground, background, reverse, normal) to
  3289.  * the color specified by name. 
  3290.  */
  3291. LOCAL void
  3292. SetColorAttribute (COLORREF *cf, char *colorName)
  3293. {
  3294.     MSWINColor        *ct;
  3295.     int            i;
  3296.     
  3297.     for (ct = MSWINColorTable; ct->colorName != NULL; ++ct) {
  3298.     if (strcmpi (colorName, ct->colorName) == 0) goto FoundColor;
  3299.     }
  3300.     
  3301.     /* color name not in table.  Try converting RGB string. */
  3302.     ConvertRGBString (colorName, cf);
  3303.     return;
  3304.     
  3305. FoundColor:
  3306.     *cf = ct->colorRef;
  3307.  
  3308.     /* Redraw screen. */
  3309.     gpTTYInfo->screenDirty = TRUE;
  3310.     gpTTYInfo->eraseScreen = TRUE;
  3311.     InvalidateRect (ghTTYWnd, NULL, FALSE);
  3312. }
  3313.  
  3314.  
  3315.  
  3316. /*
  3317.  * Convert a string to an integer.
  3318.  */
  3319. LOCAL BOOL
  3320. ScanInt (char *str, int min, int max, int *val)
  3321. {
  3322.     BOOL    numberString;
  3323.     char    *c;
  3324.     int        v;
  3325.     
  3326.     
  3327.     if (str == NULL) return (FALSE);
  3328.     if (*str == '\0' || strlen (str) > 9) return (FALSE);
  3329.     numberString = TRUE;
  3330.     for (c = str; *c != '\0'; ++c) {
  3331.     if (!isdigit(*c))
  3332.         return (FALSE);
  3333.     }
  3334.     v = atoi (str);
  3335.     if (v < min || v > max) 
  3336.     return (FALSE);
  3337.     *val = v;
  3338.     return (TRUE);
  3339. }
  3340.  
  3341.  
  3342.  
  3343. /*
  3344.  * Convert a RGB string to a color ref.  The string should look like:
  3345.  *    rrr,ggg,bbb
  3346.  * where rrr, ggg, and bbb are numbers between 0 and 255 that represent
  3347.  * red, gree, and blue values.  Must be comma seperated.
  3348.  * Returns:
  3349.  *    TRUE    - Successfully converted string.
  3350.  *    FALSE    - Bad format, 'cf' unchanged.
  3351.  */
  3352.  
  3353. LOCAL BOOL
  3354. ConvertRGBString (char *colorName, COLORREF *cf)
  3355. {
  3356.     int        cv;
  3357.     char    *c;
  3358.     char    *s;
  3359.     char    *p;
  3360.     char    cpy[16];
  3361.     int        rgb[3];
  3362.    
  3363.     /* Some basic tests. */
  3364.     if (colorName == NULL) return (FALSE);        /* Not Null? */
  3365.     if (strlen (colorName) > 11) return (FALSE);    /* Not too long? */
  3366.     for (s = colorName; *s != '\0'; ++s) {
  3367.     if (!isdigit (*s) && *s != ',') return (FALSE); /* Valid characters?*/
  3368.     }
  3369.     
  3370.     /* Work with a copy of string. */
  3371.     strcpy (cpy, colorName);
  3372.     s = cpy;                /* Start at beginning. */
  3373.     for (cv = 0; cv < 3; ++cv) {    /* Get three digits. */
  3374.     if (cv < 2) {            /* Expect only two commas. */
  3375.         c = strchr (s, ',');        /* Find next comma. */
  3376.         if (c == NULL) return (FALSE);
  3377.         *c = '\0';
  3378.     }
  3379.     if (*s == ',' || *s == '\0') return (FALSE);
  3380.     if (strlen (s) > 3) return (FALSE);
  3381.     rgb[cv] = atoi (s);
  3382.     if (rgb[cv] < 0 || rgb[cv] > 255) return (FALSE);
  3383.     s = c + 1;
  3384.     }
  3385.  
  3386.     *cf = RGB (rgb[0], rgb[1], rgb[2]);
  3387.     printf ("%d, %d, %d  ", rgb[0], rgb[1], rgb[2]);
  3388.     return (TRUE);
  3389. }
  3390.  
  3391.  
  3392.  
  3393.  
  3394. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  3395.  *
  3396.  *                  Toolbar setup routines.
  3397.  *
  3398.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  3399.  
  3400. LOCAL void
  3401. TBToggle (HWND hWnd)
  3402. {
  3403.     PTTYINFO        pTTYInfo;
  3404.  
  3405.     
  3406.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  3407.     if (pTTYInfo == NULL)
  3408.     return;
  3409.  
  3410.     if (pTTYInfo->toolBarSize > 0) 
  3411.     TBHide (hWnd);
  3412.     else
  3413.     TBShow (hWnd);
  3414. }
  3415.  
  3416.  
  3417.  
  3418. LOCAL void
  3419. TBPosToggle (HWND hWnd)
  3420. {
  3421.     PTTYINFO        pTTYInfo;
  3422.     RECT        rc;
  3423.  
  3424.     
  3425.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  3426.     if (pTTYInfo == NULL)
  3427.     return;
  3428.  
  3429.     pTTYInfo->toolBarTop = !pTTYInfo->toolBarTop;
  3430.     
  3431.     GetClientRect (hWnd, &rc);            /* Get TTY window size. */
  3432.     SizeTTY (hWnd, 0, (CORD)rc.bottom, (CORD)rc.right);
  3433. }
  3434.  
  3435.  
  3436.  
  3437.  
  3438. LOCAL void
  3439. TBShow (HWND hWnd)
  3440. {
  3441.     PTTYINFO        pTTYInfo;
  3442.     RECT        rc;
  3443.  
  3444.     
  3445.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  3446.     if (pTTYInfo == NULL)
  3447.     return;
  3448.  
  3449.     
  3450.     /*
  3451.      * Make sure the tool bar not already shown.
  3452.      */
  3453.     if (pTTYInfo->toolBarSize > 0)
  3454.     return;
  3455.  
  3456.  
  3457.  
  3458.     /*
  3459.      * Make procinstance for dialog funciton.
  3460.      */
  3461.     HideCaret (hWnd);
  3462.     if (gToolBarProc == NULL) 
  3463.     gToolBarProc = (DLGPROC) MakeProcInstance( (FARPROC) ToolBarProc,
  3464.                                                 ghInstance ) ;
  3465.     if (gTBBtnProc == NULL) 
  3466.     gTBBtnProc = (WNDPROC) MakeProcInstance( (FARPROC) TBBtnProc,
  3467.                         ghInstance ) ;
  3468.  
  3469.     
  3470.     /*
  3471.      * Create the dialog box.
  3472.      */
  3473.     pTTYInfo->hTBWnd = CreateDialog (ghInstance,
  3474.             MAKEINTRESOURCE (pTTYInfo->curToolBarID),
  3475.             hWnd,
  3476.             gToolBarProc);
  3477.     if (pTTYInfo->hTBWnd == NULL) {
  3478.     ShowCaret (hWnd);
  3479.     return;
  3480.     }
  3481.  
  3482.     SetFocus (hWnd);
  3483.  
  3484.  
  3485.     /*
  3486.      * Adjust the window size.
  3487.      */
  3488.     GetWindowRect (pTTYInfo->hTBWnd, &rc);    /* Get Toolbar size. */
  3489.     pTTYInfo->toolBarSize = rc.bottom - rc.top;
  3490.  
  3491.     GetClientRect (hWnd, &rc);            /* Get TTY window size. */
  3492.     SizeTTY (hWnd, 0, (CORD)rc.bottom, (CORD)rc.right);
  3493.     ShowCaret (hWnd);
  3494. }
  3495.  
  3496.  
  3497.  
  3498.  
  3499. LOCAL void
  3500. TBHide (HWND hWnd)
  3501. {
  3502.     PTTYINFO        pTTYInfo;
  3503.     RECT        rc;
  3504.     
  3505.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  3506.     if (pTTYInfo == NULL)
  3507.     return;
  3508.  
  3509.  
  3510.     if (pTTYInfo->toolBarSize == 0)
  3511.     return;
  3512.  
  3513.     DestroyWindow (pTTYInfo->hTBWnd);
  3514.     pTTYInfo->hTBWnd = NULL;
  3515.     if (pTTYInfo->toolBarBtns != NULL) 
  3516.     MemFree (pTTYInfo->toolBarBtns);
  3517.     pTTYInfo->toolBarBtns = NULL;
  3518.  
  3519.     
  3520.     /*
  3521.      * Adjust the window size.
  3522.      */
  3523.     pTTYInfo->toolBarSize = 0;
  3524.     GetClientRect (hWnd, &rc);
  3525.     SizeTTY (hWnd, 0, (CORD)rc.bottom, (CORD)rc.right);
  3526. }
  3527.  
  3528.  
  3529.  
  3530. LOCAL void
  3531. TBSwap (HWND hWnd, int newID)
  3532. {
  3533.     PTTYINFO        pTTYInfo;
  3534.     RECT        rc;
  3535.     
  3536.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  3537.     if (pTTYInfo == NULL)
  3538.     return;
  3539.  
  3540.     if (pTTYInfo->toolBarSize == 0 || pTTYInfo->curToolBarID == newID)
  3541.     return;
  3542.  
  3543.     /*
  3544.      * Dispose of old tool bar window.
  3545.      */
  3546.     HideCaret (hWnd);
  3547.  
  3548.     DestroyWindow (pTTYInfo->hTBWnd);
  3549.     pTTYInfo->hTBWnd = NULL;
  3550.     if (pTTYInfo->toolBarBtns != NULL) 
  3551.     MemFree (pTTYInfo->toolBarBtns);
  3552.     pTTYInfo->toolBarBtns = NULL;
  3553.     
  3554.     
  3555.  
  3556.     /*
  3557.      * Create the new dialog box.
  3558.      */
  3559.     pTTYInfo->hTBWnd = CreateDialog (ghInstance,
  3560.             MAKEINTRESOURCE (newID),
  3561.             hWnd,
  3562.             gToolBarProc);
  3563.     if (pTTYInfo->hTBWnd == NULL) {
  3564.     ShowCaret (hWnd);
  3565.     return;
  3566.     }
  3567.     pTTYInfo->curToolBarID = newID;
  3568.     SetFocus (hWnd);        /* Return focus to parent. */
  3569.  
  3570.     
  3571.     /*
  3572.      * Fit new tool bar into old tool bars position.  This assumes that
  3573.      * all tool bars are about the same height.
  3574.      */
  3575.     GetClientRect (hWnd, &rc);            /* Get TTY window size. */
  3576.     if (pTTYInfo->toolBarTop) 
  3577.     /* Position at top of window. */
  3578.     SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP, 
  3579.         0, 0, 
  3580.         rc.right, pTTYInfo->toolBarSize, 
  3581.         SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
  3582.     else
  3583.     /* Position at bottom of window. */
  3584.     SetWindowPos (pTTYInfo->hTBWnd, HWND_TOP, 
  3585.         0, pTTYInfo->ySize - pTTYInfo->toolBarSize, 
  3586.         rc.right, pTTYInfo->toolBarSize, 
  3587.         SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
  3588.     
  3589.     ShowCaret (hWnd);
  3590. }
  3591.  
  3592.     
  3593.  
  3594.  
  3595.  
  3596. BOOL FAR PASCAL __export 
  3597. ToolBarProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  3598. {
  3599.     RECT        rc;
  3600.     BOOL        ret;
  3601.     int            height;
  3602.     HBRUSH        hBrush;
  3603.     HWND        hCld;
  3604.     int            btnCount;
  3605.     int            i;
  3606.     PTTYINFO        pTTYInfo;
  3607.     
  3608.     
  3609.     pTTYInfo = gpTTYInfo;
  3610.     
  3611.     ret = FALSE;
  3612.     switch (msg) {
  3613.         
  3614.     case WM_INITDIALOG:
  3615.     /* Fit dialog to window. */
  3616.     GetWindowRect (hWnd, &rc);
  3617.     height = rc.bottom - rc.top;
  3618.     GetClientRect (GetParent (hWnd), &rc);
  3619.     SetWindowPos (hWnd, HWND_TOP, 0, 0, rc.right, height, 
  3620.             SWP_NOZORDER | SWP_NOACTIVATE);
  3621.  
  3622.     /* Count child windows.*/
  3623.     btnCount = 0;
  3624.     for (hCld = GetWindow (hWnd, GW_CHILD); 
  3625.          hCld; 
  3626.          hCld = GetWindow (hCld, GW_HWNDNEXT))
  3627.         ++btnCount;
  3628.  
  3629.     /* Allocate a list of previous child procs. */
  3630.     if (pTTYInfo->toolBarBtns != NULL)
  3631.         MemFree (pTTYInfo->toolBarBtns);
  3632.     pTTYInfo->toolBarBtns = MemAlloc (sizeof (BtnList) * (btnCount + 1));
  3633.     
  3634.     /* Subclass all child windows. */
  3635.     for (i = 0, hCld = GetWindow (hWnd, GW_CHILD); 
  3636.         hCld; 
  3637.         ++i, hCld = GetWindow (hCld, GW_HWNDNEXT)) {
  3638.         pTTYInfo->toolBarBtns[i].wndID = GET_ID (hCld);
  3639.         pTTYInfo->toolBarBtns[i].wndProc = (WNDPROC) GetWindowLong (hCld, 
  3640.                             GWL_WNDPROC);
  3641.         SetWindowLong (hCld, GWL_WNDPROC, (DWORD)TBBtnProc);
  3642.         }
  3643.         pTTYInfo->toolBarBtns[i].wndID = 0;
  3644.     pTTYInfo->toolBarBtns[i].wndProc = NULL;
  3645.  
  3646.     ret = FALSE;
  3647.     break;
  3648.     
  3649.  
  3650.     case WM_COMMAND:
  3651.     if (wParam >= KS_RANGESTART && wParam <= KS_RANGEEND){
  3652.         ProcessMenuItem (GetParent (hWnd), wParam);
  3653.         /* Set input focus back to parent. */
  3654.         SetFocus (GetParent (hWnd));
  3655.         ret = TRUE;
  3656.         break;
  3657.     }
  3658.     break;
  3659.  
  3660. #ifdef    WIN32
  3661.     case WM_CTLCOLORBTN:
  3662. #else
  3663.     case WM_CTLCOLOR:
  3664. #endif
  3665.     if (HIWORD (lParam) == CTLCOLOR_DLG) {
  3666.         hBrush = CreateSolidBrush (GetSysColor (COLOR_ACTIVEBORDER));
  3667.         return ((BOOL) hBrush);
  3668.         }
  3669.     }
  3670.     return (ret);
  3671. }
  3672.  
  3673.  
  3674.  
  3675.  
  3676.  
  3677. /*
  3678.  * Subclass toolbar button windows.
  3679.  *
  3680.  * These buttons will automatically return the input focus to 
  3681.  * the toolbar's parent
  3682.  */
  3683. LRESULT FAR PASCAL __export
  3684. TBBtnProc (HWND hBtn, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3685. {
  3686.     PTTYINFO        pTTYInfo;
  3687.     HWND        hPrnt;
  3688.     int            i;
  3689.     WORD        id;
  3690.     LRESULT        ret;
  3691.     WNDPROC        wndProc;
  3692.     
  3693.     
  3694.     /*
  3695.      * Find previous window proc.
  3696.      */
  3697.     pTTYInfo = gpTTYInfo;
  3698.     id = GET_ID (hBtn);
  3699.     for (i = 0; pTTYInfo->toolBarBtns[i].wndID != 0; ++i)
  3700.     if (pTTYInfo->toolBarBtns[i].wndID == id)
  3701.         goto FoundWindow;
  3702.     /* Whoops!  Didn't find window, don't know how to pass message. */
  3703.     return (0);
  3704.     
  3705.     
  3706. FoundWindow:
  3707.     wndProc = pTTYInfo->toolBarBtns[i].wndProc;
  3708.      
  3709.     
  3710.  
  3711.     if (uMsg == WM_LBUTTONUP || uMsg == WM_MBUTTONUP || uMsg == WM_RBUTTONUP) {
  3712.     /*
  3713.      * On mouse button up restore input focus to IDC_RESPONCE, which
  3714.      * processes keyboard input.
  3715.      */
  3716.     ret = CallWindowProc (wndProc, hBtn, uMsg, wParam, lParam);
  3717.     hPrnt = GetParent (GetParent (hBtn));
  3718.     if (hPrnt)
  3719.         SetFocus (hPrnt);
  3720.     return (ret);
  3721.     }
  3722.     
  3723.     return (CallWindowProc (wndProc, hBtn, uMsg, wParam, lParam));
  3724. }
  3725.  
  3726.  
  3727. #ifdef ACCELERATORS
  3728. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  3729.  *
  3730.  *      Accelorator key routines.
  3731.  *
  3732.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  3733. LOCAL void
  3734. AccelCtl (HWND hWnd, int ctl, BOOL saveChange)
  3735. {
  3736.     PTTYINFO        pTTYInfo;
  3737.     BOOL        load, changed;
  3738.     
  3739.     
  3740.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  3741.     if (pTTYInfo == NULL)
  3742.     return;
  3743.  
  3744.     load = FALSE;
  3745.     if (ctl == ACCEL_LOAD) {
  3746.     load = TRUE;
  3747.     }
  3748.     else if (ctl == ACCEL_TOGGLE) {
  3749.     load = pTTYInfo->hAccel == NULL;
  3750.     }
  3751.     
  3752.     
  3753.     changed = FALSE;
  3754.     if (load && pTTYInfo->hAccel == NULL) {
  3755.     /* Load em up. */
  3756.     pTTYInfo->hAccel = LoadAccelerators (ghInstance, 
  3757.                     MAKEINTRESOURCE (IDR_ACCEL_PINE));
  3758.     changed = TRUE;
  3759.     }
  3760.     else {
  3761.     /* unload em. */
  3762.     FreeResource (pTTYInfo->hAccel);    
  3763.     pTTYInfo->hAccel = NULL;
  3764.     changed = TRUE;
  3765.     }
  3766.     
  3767.     if (changed && saveChange) 
  3768.     DidResize (pTTYInfo);
  3769. }
  3770. #endif        
  3771.  
  3772.  
  3773.  
  3774. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  3775.  *
  3776.  *                  Mouse Selection routines
  3777.  *
  3778.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  3779.  
  3780. LOCAL BOOL    SelSelected = FALSE;
  3781. LOCAL BOOL    SelTracking = FALSE;
  3782. LOCAL int    SelAnchorRow;
  3783. LOCAL int    SelAnchorCol;
  3784. LOCAL int    SelPointerRow;
  3785. LOCAL int    SelPointerCol;
  3786. typedef struct {
  3787.     CHAR    *pRow;
  3788.     int        len;
  3789. } CopyRow;
  3790.  
  3791. LOCAL void
  3792. SelRSet (int oStart, int oEnd)
  3793. {
  3794.     CharAttrib    *pca;
  3795.     
  3796.     for (pca = gpTTYInfo->pAttrib + oStart; oStart < oEnd; ++pca, ++oStart)
  3797.     *pca |= CHAR_ATTR_SEL;
  3798. }
  3799.  
  3800.  
  3801. LOCAL void
  3802. SelRClear (int oStart, int oEnd)
  3803. {
  3804.     CharAttrib    *pca;
  3805.     
  3806.     for (pca = gpTTYInfo->pAttrib + oStart; oStart < oEnd; ++pca, ++oStart)
  3807.     *pca &= ~CHAR_ATTR_SEL;
  3808. }
  3809.  
  3810.  
  3811. LOCAL void
  3812. SelRInvalidate (int oStart, int oEnd)
  3813. {
  3814.     RECT    rect;
  3815.     int        sRow, sCol;
  3816.     int        eRow, eCol;
  3817.     
  3818.     sRow = oStart / gpTTYInfo->actNColumn;
  3819.     sCol = oStart % gpTTYInfo->actNColumn;
  3820.     eRow = oEnd   / gpTTYInfo->actNColumn;
  3821.     eCol = oEnd   % gpTTYInfo->actNColumn;
  3822.     
  3823.     rect.top = (sRow * gpTTYInfo->yChar) + gpTTYInfo->yOffset;
  3824.     rect.bottom = ((eRow+1) * gpTTYInfo->yChar) + gpTTYInfo->yOffset;
  3825.     if (sRow == eRow) {
  3826.     rect.left = (sCol * gpTTYInfo->xChar) + gpTTYInfo->xOffset;
  3827.     rect.right = ((eCol+1) * gpTTYInfo->xChar) + gpTTYInfo->xOffset;
  3828.     } else {
  3829.     rect.left = gpTTYInfo->xOffset;
  3830.     rect.right = (gpTTYInfo->actNColumn * gpTTYInfo->xChar) + 
  3831.             gpTTYInfo->xOffset;
  3832.     }
  3833.     InvalidateRect (ghTTYWnd, &rect, FALSE);
  3834. }
  3835.  
  3836.  
  3837.  
  3838. /*
  3839.  * Start a mouse selection.
  3840.  */
  3841. LOCAL void
  3842. SelStart (int nRow, int nColumn)
  3843. {
  3844.     SelClear ();
  3845.     SelTracking = TRUE;
  3846.     SelSelected = TRUE;
  3847.     SelPointerRow = SelAnchorRow = nRow;
  3848.     SelPointerCol = SelAnchorCol = nColumn;
  3849.     return;
  3850. }
  3851.  
  3852.  
  3853. /*
  3854.  * Finish a mouse selection.
  3855.  */
  3856. LOCAL void
  3857. SelFinish (int nRow, int nColumn)
  3858. {
  3859.     if (nRow == SelAnchorRow && nColumn == SelAnchorCol) {
  3860.     /* Mouse up in same place it went down - no selection. */
  3861.     SelClear ();
  3862.     }
  3863.     else {
  3864.     /* Update screen selection and set final position of mouse
  3865.      * then turn of mouse tracking.  Selection remains in effect
  3866.      * until SelClear is called. */
  3867.     SelTrackMouse (nRow, nColumn);
  3868.     SelTracking = FALSE;
  3869.     }
  3870. }
  3871.  
  3872. LOCAL void
  3873. SelClear (void)
  3874. {
  3875.     int        a, p;
  3876.     int        s, e;
  3877.     CharAttrib    *pca;
  3878.  
  3879.     
  3880.     if (!SelSelected) 
  3881.     return;
  3882.  
  3883.  
  3884.     /* Convert the anchor and point coordinates to offsets then
  3885.      * order the offsets. */
  3886.     a = (SelAnchorRow * gpTTYInfo->actNColumn) + SelAnchorCol;
  3887.     p = (SelPointerRow * gpTTYInfo->actNColumn) + SelPointerCol;
  3888.     if (a < p) {
  3889.     s = a;
  3890.     e = p;
  3891.     } else {
  3892.     s = p;
  3893.     e = a;
  3894.     }
  3895.  
  3896.     /* Clear selected attribute of those cells in range. */
  3897.     SelRClear (s, e);
  3898.     SelRInvalidate (s, e);
  3899.     SelSelected = FALSE;
  3900.     SelTracking = FALSE;
  3901. }
  3902.  
  3903.  
  3904. /*
  3905.  * Update the position of the mouse point.
  3906.  */
  3907. LOCAL void
  3908. SelTrackXYMouse (int xPos, int yPos)
  3909. {
  3910.     int        nRow;
  3911.     int        nColumn;
  3912.     
  3913.     nColumn = (xPos - gpTTYInfo->xOffset) / gpTTYInfo->xChar;
  3914.     nRow = (yPos - gpTTYInfo->yOffset) / gpTTYInfo->yChar;
  3915.  
  3916.     SelTrackMouse (nRow, nColumn);
  3917. }
  3918.  
  3919.  
  3920. /*
  3921.  * Update the position of the mouse point.
  3922.  */
  3923. LOCAL void
  3924. SelTrackMouse (int nRow, int nColumn)
  3925. {
  3926.     int        a, p, n;
  3927.     int        s, e;
  3928.     
  3929.     if (!SelTracking)
  3930.     return;
  3931.  
  3932.     /* Constrain the cel position to be on the screen.  But allow
  3933.      * for the Column to be one past the right edge of the screen so
  3934.      * the user can select the right most cel of a row. */
  3935.     nColumn = max (0, nColumn);
  3936.     nColumn = min (gpTTYInfo->actNColumn, nColumn);
  3937.     nRow = max (0, nRow);
  3938.     nRow = min (gpTTYInfo->actNRow-1, nRow);
  3939.  
  3940.  
  3941.     /* Convert the anchor, previous mouse position, and new mouse
  3942.      * position to offsets. */
  3943.     a = (SelAnchorRow * gpTTYInfo->actNColumn) + SelAnchorCol;
  3944.     p = (SelPointerRow * gpTTYInfo->actNColumn) + SelPointerCol;
  3945.     n = (nRow * gpTTYInfo->actNColumn) + nColumn;
  3946.     
  3947.     /* If previous position same as current position, do nothing. */
  3948.     if (p == n)
  3949.     return;
  3950.  
  3951.     /* there are six possible orderings of the points, each with
  3952.      * a different action:
  3953.      *    order        clear        set        redraw
  3954.      *    n p a                n - p        n - p
  3955.      *    p n a        p - n                p - n
  3956.      *    p a n        p - a        a - n        p - n
  3957.      *    a p n                p - n        p - n
  3958.      *  a n p        n - p                n - p
  3959.      *  n a p        a - p        n - a        n - p
  3960.      */
  3961.     if (p < a) {
  3962.     if (n < a) {
  3963.         if (n < p) {
  3964.         SelRSet (n, p);
  3965.         SelRInvalidate (n, p);
  3966.         } else {
  3967.         SelRClear (p, n);
  3968.         SelRInvalidate (p, n);
  3969.         }
  3970.     } else {
  3971.         SelRClear (p, a);
  3972.         SelRSet (a, n);
  3973.         SelRInvalidate (p, n);
  3974.         }
  3975.     } else {
  3976.     if (n > a) {
  3977.         if (n > p) {
  3978.         SelRSet (p, n);
  3979.         SelRInvalidate (p, n);
  3980.         } else {
  3981.         SelRClear (n, p);
  3982.         SelRInvalidate (n, p);
  3983.         }
  3984.     } else {
  3985.         SelRClear (a, p);
  3986.         SelRSet (n, a);
  3987.         SelRInvalidate (n, p);
  3988.         }
  3989.     }
  3990.  
  3991.     /* Set new pointer. */
  3992.     SelPointerRow = nRow;
  3993.     SelPointerCol = nColumn;
  3994. }
  3995.  
  3996.  
  3997.  
  3998. LOCAL BOOL
  3999. SelAvailable (void)
  4000. {
  4001.     return (SelSelected);
  4002. }
  4003.  
  4004. /*
  4005.  * Copy screen data to clipboard.  Actually appends data from screen to 
  4006.  * existing handle so as we can implement a "Copy Append" to append to
  4007.  * existing clipboard data.  
  4008.  *
  4009.  * The screen does not have real line terminators.  We decide where the 
  4010.  * actual screen data ends by scanning the line (row) from end backwards
  4011.  * to find the first non-space.
  4012.  * 
  4013.  * I don't know how many bytes of data I'll be appending to the clipboard.
  4014.  * So I implemented in two passes.  The first finds all the row starts
  4015.  * and length while the second copies the data.
  4016.  */
  4017.  
  4018. LOCAL void
  4019. SelDoCopy (HANDLE hCB, DWORD lenCB)
  4020. {
  4021.     HANDLE        newCB;        /* Used in reallocation. */
  4022.     CHAR        *pCB;        /* Points to CB data. */    
  4023.     CHAR        *p2;        /* Temp pointer to screen data. */
  4024.     int            sRow, eRow;    /* Start and End Rows. */
  4025.     int            sCol, eCol;    /* Start and End columns. */
  4026.     int            row, c1, c2;    /* temp row and column indexes. */
  4027.     int            totalLen;    /* total len of new data. */
  4028.     CopyRow        *rowTable, *rp;    /* pointers to table of rows. */
  4029.     BOOL        noLastCRLF;
  4030.     
  4031.  
  4032.     if (OpenClipboard (ghTTYWnd)) {        /* ...and we get the CB. */
  4033.       if (EmptyClipboard ()) {        /* ...and clear previous CB.*/
  4034.  
  4035.  
  4036.     /* Find the start and end row and column. */
  4037.     if ( (SelAnchorRow * gpTTYInfo->actNColumn) + SelAnchorCol < 
  4038.          (SelPointerRow * gpTTYInfo->actNColumn) + SelPointerCol) {
  4039.         sRow = SelAnchorRow;
  4040.         sCol = SelAnchorCol;
  4041.         eRow = SelPointerRow;
  4042.         eCol = SelPointerCol;
  4043.     }
  4044.     else {
  4045.         sRow = SelPointerRow;
  4046.         sCol = SelPointerCol;
  4047.         eRow = SelAnchorRow;
  4048.         eCol = SelAnchorCol;
  4049.     }
  4050.  
  4051.     /* Allocate a table in which we store info on rows. */
  4052.     rowTable = (CopyRow *) MemAlloc (sizeof (CopyRow) * (eRow-sRow+1));
  4053.     if (rowTable == NULL)
  4054.         goto Fail1;
  4055.  
  4056.     /* Find the start and length of each row. */
  4057.     totalLen = 0;
  4058.     for (row = sRow, rp = rowTable; row <= eRow; ++row, ++rp) {
  4059.         /* Find beginning and end columns, which depends on if
  4060.          * this is the first or last row in the selection. */
  4061.         c1 = (row == sRow ? sCol : 0);
  4062.         c2 = (row == eRow ? eCol : gpTTYInfo->actNColumn);
  4063.  
  4064.         /* Calculate pointer to beginning of this line. */
  4065.         rp->pRow = gpTTYInfo->pScreen + 
  4066.             ((row * gpTTYInfo->actNColumn) + c1);
  4067.  
  4068.         /* Back down from end column to find first non space. 
  4069.          * noLastCRLF indicates if it looks like the selection
  4070.          * should include a CRLF on the end of the line.  It
  4071.          * gets set for each line, but only the setting for the
  4072.          * last line in the selection is remembered (which is all
  4073.          * we're interested in). */
  4074.         p2 = gpTTYInfo->pScreen + 
  4075.             ((row * gpTTYInfo->actNColumn) + c2);
  4076.         noLastCRLF = TRUE;
  4077.         while (c2 > c1) {
  4078.         if (*(p2-1) != ' ')
  4079.             break;
  4080.         noLastCRLF = FALSE;
  4081.         --c2;
  4082.         --p2;
  4083.         }
  4084.  
  4085.         /* Calculate size of line, then increment totalLen plus 2 for
  4086.          * the CRLF which will terminate each line. */
  4087.         rp->len = c2 - c1;
  4088.         totalLen += rp->len + 2;
  4089.     }
  4090.  
  4091.     /* Reallocate the memory block.  Add one byte for null terminator. */
  4092.     newCB = GlobalReAlloc (hCB, lenCB + totalLen + 1, 0);
  4093.     if (newCB == NULL)
  4094.         goto Fail2;
  4095.     hCB = newCB;
  4096.  
  4097.     pCB = GlobalLock (hCB);
  4098.     if (pCB == NULL)
  4099.         goto Fail2;
  4100.  
  4101.     /* Append each of the rows, deliminated by a CRLF. */
  4102.     pCB += lenCB;
  4103.     for (row = sRow, rp = rowTable; row <= eRow; ++row, ++rp) {
  4104.         if (rp->len > 0) {
  4105.         memcpy (pCB, rp->pRow, rp->len);
  4106.         pCB += rp->len;
  4107.         }
  4108.         if (row < eRow || !noLastCRLF) {
  4109.         *pCB++ = ASCII_CR;
  4110.         *pCB++ = ASCII_LF;
  4111.         }
  4112.     }
  4113.     *pCB = '\0';            /* Null terminator. */
  4114.     MemFree (rowTable);
  4115.     GlobalUnlock (hCB);
  4116.  
  4117.     /* Attempt to pass the data to the clipboard, then release clipboard
  4118.      * and exit function. */
  4119.     if (SetClipboardData (CF_TEXT, hCB) == NULL)
  4120.               /* Failed!  Free the data. */
  4121.               GlobalFree (hCB);
  4122.     CloseClipboard ();
  4123.       }
  4124.     }
  4125.     return;
  4126.     
  4127.     
  4128.     /* Error exit. */
  4129. Fail2:    MemFree (rowTable);
  4130. Fail1:    GlobalFree (hCB);
  4131.     CloseClipboard ();
  4132.     return;
  4133. }
  4134.  
  4135.  
  4136.  
  4137.  
  4138.     
  4139.  
  4140. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4141.  *
  4142.  *                  Upper Layer Screen routines.
  4143.  *
  4144.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  4145.  
  4146. /*
  4147.  * Flush the write accumulator buffer.
  4148.  */
  4149. LOCAL void
  4150. FlushWriteAccum (void)
  4151. {
  4152.     if (gpTTYInfo->writeAccumCount > 0) {
  4153.     WriteTTYText (ghTTYWnd, gpTTYInfo->writeAccum, 
  4154.                     gpTTYInfo->writeAccumCount);
  4155.     gpTTYInfo->writeAccumCount = 0;
  4156.     }
  4157. }
  4158.  
  4159.  
  4160.  
  4161. /*
  4162.  * Return the application instance.
  4163.  */
  4164. WINHAND
  4165. mswin_gethinstance ()
  4166. {
  4167.     return ((WINHAND)ghInstance);
  4168. }
  4169.  
  4170.  
  4171. WINHAND
  4172. mswin_gethwnd ()
  4173. {
  4174.     return ((WINHAND)ghTTYWnd);
  4175. }
  4176.  
  4177.  
  4178.  
  4179. /*
  4180.  *    Called to get mouse event.
  4181.  */
  4182. int
  4183. mswin_getmouseevent (MEvent * pMouse)
  4184. {
  4185.     return (MQGet (pMouse));
  4186. }
  4187.  
  4188.  
  4189. /*
  4190.  * Set up debugging stuff.
  4191.  */
  4192. mswin_setdebug (int debug, FILE *debugfile)
  4193. {
  4194.     /* Accept new file only if we don't already have a file. */
  4195.     if (mswin_debugfile == 0) {
  4196.     mswin_debug = debug;
  4197.     mswin_debugfile = debugfile;
  4198.     MemDebug (debug, mswin_debugfile);
  4199.     }
  4200. }
  4201.  
  4202.  
  4203.  
  4204. /*
  4205.  * Event handler to deal with File Drop events
  4206.  */
  4207. LOCAL BOOL  
  4208. ProcessTTYFileDrop (HANDLE wDrop)
  4209. {
  4210.     HDROP hDrop = wDrop;
  4211.     POINT pos;
  4212.     int   col, row, i, n;
  4213.     char  fname[1024];
  4214.  
  4215.     if(!gpTTYInfo->dndhandler)
  4216.       return(0);
  4217.  
  4218.     /* translate drop point to character cell */
  4219.     DragQueryPoint(hDrop, &pos);
  4220.     col = (pos.x - gpTTYInfo->xOffset) / gpTTYInfo->xChar;
  4221.     if (pos.x < gpTTYInfo->xOffset)
  4222.     --col;
  4223.     row = (pos.y - gpTTYInfo->yOffset) / gpTTYInfo->yChar;
  4224.     if (pos.y < gpTTYInfo->yOffset)
  4225.     --row;
  4226.  
  4227.     for(n = DragQueryFile(hDrop, -1, NULL, 0), i = 0; i < n; i++){
  4228.     DragQueryFile(hDrop, i, fname, 1024);
  4229.     gpTTYInfo->dndhandler (row, col, fname);
  4230.     }
  4231.  
  4232.     DragFinish(hDrop);
  4233.     return(1);
  4234. }
  4235.  
  4236. /*
  4237.  * Set a callback to deal with Drag 'N Drop events
  4238.  */
  4239. int
  4240. mswin_setdndcallback (int (*cb)())
  4241. {
  4242.     if(gpTTYInfo->dndhandler)
  4243.       gpTTYInfo->dndhandler = NULL;
  4244.  
  4245.     if(cb){
  4246.     gpTTYInfo->dndhandler = cb;
  4247.     DragAcceptFiles(ghTTYWnd, TRUE);
  4248.     }
  4249.  
  4250.     return(1);
  4251. }
  4252.  
  4253. /*
  4254.  * Clear previously installed callback to handle Drag 'N Drop
  4255.  * events
  4256.  */
  4257. int
  4258. mswin_cleardndcallback ()
  4259. {
  4260.     gpTTYInfo->dndhandler = NULL;
  4261.     DragAcceptFiles(ghTTYWnd, FALSE);
  4262.     return(1);
  4263. }
  4264.  
  4265.  
  4266.  
  4267. /*
  4268.  * Set a callback for function 'ch'
  4269.  */
  4270. int
  4271. mswin_setresizecallback (int (*cb)())
  4272. {
  4273.     int        i;
  4274.     int        e;
  4275.     
  4276.     
  4277.     /*
  4278.      * Look through whole array for this call back function.  Don't
  4279.      * insert duplicate.  Also look for empty slot.
  4280.      */
  4281.     e = -1;
  4282.     for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i) {
  4283.     if (gpTTYInfo->resizer[i] == cb) 
  4284.         return (0);
  4285.         if (e == -1 && gpTTYInfo->resizer[i] == NULL) 
  4286.         e = i;
  4287.     }
  4288.     
  4289.     /*
  4290.      * Insert in empty slot or return an error.
  4291.      */
  4292.     if (e != -1) {
  4293.     gpTTYInfo->resizer[e] = cb;
  4294.     return (0);
  4295.     }
  4296.     return (-1);
  4297. }
  4298.  
  4299. /*
  4300.  * Clear all instances of the callback function 'cb'
  4301.  */
  4302. int
  4303. mswin_clearresizecallback (int (*cb)())
  4304. {
  4305.     int        i;
  4306.     int        status;
  4307.     
  4308.     status = -1;
  4309.     for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i) {
  4310.     if (gpTTYInfo->resizer[i] == cb) {
  4311.         gpTTYInfo->resizer[i] = NULL;
  4312.         status = 0;
  4313.     }
  4314.     }
  4315.     return (status);
  4316. }
  4317.  
  4318.  
  4319. void
  4320. mswin_beginupdate (void)
  4321. {
  4322.     gpTTYInfo->fMassiveUpdate = TRUE;
  4323. }
  4324.  
  4325.  
  4326.  
  4327. void
  4328. mswin_endupdate (void)
  4329. {
  4330.     gpTTYInfo->fMassiveUpdate = FALSE;
  4331.     MoveTTYCursor (ghTTYWnd);
  4332. }
  4333.  
  4334.  
  4335.  
  4336. int
  4337. mswin_setwindow (char *fontName, char *fontSize, char *fontStyle, 
  4338.     char *windowPosition)
  4339. {
  4340.     LOGFONT        newFont;
  4341.     int            newHeight;
  4342.     HDC            hDC;
  4343.     int            ppi;
  4344.     RECT        wndRect, cliRect;
  4345.     char        *c;
  4346.     char        *n;
  4347.     int            i;
  4348.     BOOL        toolBar = FALSE;
  4349.     BOOL        toolBarTop = TRUE;
  4350.     BOOL        useAccel = FALSE;
  4351.     BOOL        numberString;
  4352.     int            wColumns, wRows;
  4353.     int            wXPos, wYPos;
  4354.     int            wXBorder, wYBorder;
  4355.     int            wXSize, wYSize;
  4356.     char        wp[WIN_POS_STR_MAX_LEN + 1];
  4357.     
  4358.     
  4359. #ifdef SDEBUG
  4360.     if (mswin_debug >= 5) 
  4361.     fprintf (mswin_debugfile, "mswin_setwindow:::  entered, minimized:  %d\n",
  4362.         gpTTYInfo->fMinimized);
  4363. #endif
  4364.  
  4365.     /* Require a font name to set font info. */
  4366.     if (fontName != NULL && *fontName != '\0' && 
  4367.         strlen (fontName) <= LF_FACESIZE - 1) {
  4368.         
  4369.     hDC = GetDC (ghTTYWnd);
  4370.     ppi = GetDeviceCaps (hDC, LOGPIXELSY);
  4371.     ReleaseDC (ghTTYWnd, hDC);
  4372.  
  4373.     /* Default height, then examin the requested fontSize. */
  4374.     newFont.lfHeight =  -MulDiv (12, ppi, 72);
  4375.     if (ScanInt (fontSize, FONT_MIN_SIZE, FONT_MAX_SIZE, &newHeight)){
  4376.         newHeight = abs (newHeight);
  4377.         newFont.lfHeight = -MulDiv (newHeight, ppi, 72);
  4378.         }
  4379.     
  4380.     /* Default font style, then read requested style. */
  4381.     newFont.lfWeight =         0;
  4382.     newFont.lfItalic =         0;
  4383.     if (fontStyle != NULL) {
  4384.         _strlwr (fontStyle);
  4385.         if (strstr (fontStyle, "bold"))
  4386.         newFont.lfWeight = FW_BOLD;
  4387.         if (strstr (fontStyle, "italic"))
  4388.         newFont.lfItalic = 1;
  4389.     }
  4390.     
  4391.     /* Everything else takes the default. */
  4392.     newFont.lfWidth =          0;
  4393.     newFont.lfEscapement =     0;
  4394.     newFont.lfOrientation =    0;
  4395.     newFont.lfUnderline =      0;
  4396.     newFont.lfStrikeOut =      0;
  4397.     newFont.lfCharSet =        ANSI_CHARSET;
  4398.     newFont.lfOutPrecision =   OUT_DEFAULT_PRECIS;
  4399.     newFont.lfClipPrecision =  CLIP_DEFAULT_PRECIS;
  4400.     newFont.lfQuality =        DEFAULT_QUALITY;
  4401.     newFont.lfPitchAndFamily = FIXED_PITCH;
  4402.     strcpy (newFont.lfFaceName, fontName);
  4403.     ResetTTYFont (ghTTYWnd, gpTTYInfo, &newFont);
  4404.     }
  4405.     
  4406.     /*
  4407.      * Set window position.  String format is:  CxR+X+Y
  4408.      * Where C is the number of columns, R is the number of rows,
  4409.      * and X and Y specify the top left corner of the window.
  4410.      */
  4411.     if (windowPosition != NULL && *windowPosition != '\0') {
  4412.     if (strlen(windowPosition) > WIN_POS_STR_MAX_LEN) return (0);
  4413.     strcpy (wp, windowPosition);
  4414.     
  4415.     /* Flag characters are at the end of the string.  Strip them
  4416.      * off till we get to a number. */
  4417.     i = strlen (wp) - 1;
  4418.     while (i > 0 && (*(wp+i) < '0' || *(wp+i) > '9')) {
  4419.         if (*(wp+i) == 't' || *(wp+i) == 'b') {
  4420.         toolBar = TRUE;
  4421.         toolBarTop = (*(wp+i) == 't');
  4422.         }
  4423.         if (*(wp+i) == 'd')
  4424.         gfUseDialogs = TRUE;
  4425. #ifdef ACCELERATORS
  4426.         if (*(wp+i) == 'a')
  4427.             AccelCtl (ghTTYWnd, ACCEL_LOAD, FALSE);
  4428. #endif    
  4429.         *(wp+i) = 0;
  4430.         --i;
  4431.         }
  4432.     
  4433.     /* Look for Columns, deliminated by 'x'. */
  4434.     c = strchr (wp, 'x');
  4435.     if (c == NULL) return (0);
  4436.     *c = '\0';
  4437.     if (!ScanInt (wp, 0, 9999, &wColumns))    return (0);
  4438.  
  4439.     /* Look for Rows, deliminated by '+'. */
  4440.     n = c + 1;
  4441.     c = strchr (n, '+');
  4442.     if (c == NULL) return (0);
  4443.     *c = '\0';
  4444.     if (!ScanInt (n, 0, 9999, &wRows))    return (0);
  4445.     
  4446.     /* Look for X position, deliminated by '+'. */
  4447.     n = c + 1;
  4448.     c = strchr (n, '+');
  4449.     if (c == NULL) return (0);
  4450.     *c = '\0';
  4451.     if (!ScanInt (n, 0, 9999, &wXPos))    return (0);
  4452.     
  4453.     /* And get Y position, deliminated by end of string. */
  4454.     n = c + 1;
  4455.     if (!ScanInt (n, 0, 9999, &wYPos))    return (0);
  4456.     
  4457.     
  4458.     /* Get the current window rect and client area. */
  4459.     GetWindowRect (ghTTYWnd, &wndRect);
  4460.     GetClientRect (ghTTYWnd, &cliRect);
  4461.     
  4462.     
  4463.     /* Calculate boarder sizes. */
  4464.     wXBorder = wndRect.right - wndRect.left - cliRect.right;
  4465.     wYBorder = wndRect.bottom - wndRect.top - cliRect.bottom;
  4466.     
  4467.  
  4468.     /* Show toolbar before calculating content size. */
  4469.     if (toolBar) {
  4470.         gpTTYInfo->toolBarTop = toolBarTop;
  4471.         TBShow (ghTTYWnd);
  4472.     }
  4473.     
  4474.     
  4475.     /* Calculate new window pos and size. */
  4476.     wXSize = wXBorder + (wColumns * gpTTYInfo->xChar) + 
  4477.                         (2 * gpTTYInfo->xOffset);
  4478.     wYSize = wYBorder + (wRows * gpTTYInfo->yChar) + 
  4479.                 gpTTYInfo->toolBarSize + (2 * MARGINE_TOP);
  4480.     
  4481.     
  4482.     /* If it fits on screen, move window. */
  4483.     GetWindowRect (GetDesktopWindow(), &wndRect);
  4484.     if (wXPos + wXSize > wndRect.right) return (0);
  4485.     if (wYPos + wYSize > wndRect.bottom) return (0);
  4486.     if (!gpTTYInfo->fMinimized) 
  4487.         MoveWindow (ghTTYWnd, wXPos, wYPos, wXSize, wYSize, TRUE);
  4488.     else {
  4489.         gpTTYInfo->fDesiredSize = TRUE;
  4490.         gpTTYInfo->xDesPos = wXPos;
  4491.         gpTTYInfo->yDesPos = wYPos;
  4492.         gpTTYInfo->xDesSize = wXSize;
  4493.         gpTTYInfo->yDesSize = wYSize;
  4494.     }
  4495.     }
  4496.     return (0);
  4497. }
  4498.  
  4499.  
  4500.  
  4501. /*
  4502.  * Retreive the current font name, font size, and window position
  4503.  * These get stored in the pinerc file and will be passed to 
  4504.  * mswin_setwindow() when pine starts up.  See pinerc for comments
  4505.  * on the format.
  4506.  */
  4507. int
  4508. mswin_getwindow (char *fontName, char *fontSize, char *fontStyle, 
  4509.     char *windowPosition)
  4510. {
  4511.     HDC            hDC;
  4512.     int            ppi;
  4513.     RECT        wndRect;
  4514.     
  4515.     if (fontName != NULL) {
  4516.     strcpy (fontName, gpTTYInfo->lfTTYFont.lfFaceName);
  4517.     }
  4518.  
  4519.     if (fontSize != NULL) {
  4520.     hDC = GetDC (ghTTYWnd);
  4521.     ppi = GetDeviceCaps (hDC, LOGPIXELSY);
  4522.     ReleaseDC (ghTTYWnd, hDC);
  4523.     sprintf (fontSize, "%d", MulDiv (-gpTTYInfo->lfTTYFont.lfHeight,
  4524.                     72, ppi));
  4525.     }
  4526.     if (fontStyle != NULL) {
  4527.     char        *sep[] = {"", ", "};
  4528.     int        iSep = 0;
  4529.     
  4530.     *fontStyle = '\0';
  4531.     if (gpTTYInfo->lfTTYFont.lfWeight >= FW_BOLD) {
  4532.         strcat (fontStyle, "bold");
  4533.         iSep = 1;
  4534.         }
  4535.     if (gpTTYInfo->lfTTYFont.lfItalic) {
  4536.         strcat (fontStyle, sep[iSep]);
  4537.         strcat (fontStyle, "italic");
  4538.         }
  4539.     }
  4540.  
  4541.  
  4542.     if (windowPosition != NULL) {
  4543.     GetWindowRect (ghTTYWnd, &wndRect);
  4544.     sprintf (windowPosition, "%dx%d+%d+%d", gpTTYInfo->actNColumn, 
  4545.         gpTTYInfo->actNRow, wndRect.left, wndRect.top);
  4546.     if (gpTTYInfo->toolBarSize > 0) 
  4547.         strcat (windowPosition, gpTTYInfo->toolBarTop ? "t" : "b");
  4548.     if (gfUseDialogs)
  4549.         strcat (windowPosition, "d");
  4550.         if (gpTTYInfo->hAccel)
  4551.         strcat (windowPosition, "a");
  4552.     }
  4553.     return (0);
  4554. }
  4555.  
  4556.  
  4557. /*
  4558.  * Set the scroll range.
  4559.  */
  4560. void
  4561. mswin_setscrollrange (long max)
  4562. {
  4563.     if (max != gpTTYInfo->scrollRange) {
  4564.     if (max > 0) {
  4565.         if (max > 0x7fff) {
  4566.         gpTTYInfo->scrollScale = (float)max / (float)0x7fff;
  4567.         EnableScrollBar (ghTTYWnd, SB_VERT, ESB_ENABLE_BOTH);
  4568.         SetScrollRange (ghTTYWnd, SB_VERT, 0, 0x7fff, TRUE);
  4569.         }
  4570.         else {
  4571.         gpTTYInfo->scrollScale = 1.0;
  4572.         EnableScrollBar (ghTTYWnd, SB_VERT, ESB_ENABLE_BOTH);
  4573.         SetScrollRange (ghTTYWnd, SB_VERT, 0, (int) max, TRUE);
  4574.         }
  4575.     }
  4576.     else {
  4577.         max = 0;
  4578.         SetScrollRange (ghTTYWnd, SB_VERT, 0, 1, FALSE);
  4579.         EnableScrollBar (ghTTYWnd, SB_VERT, ESB_DISABLE_BOTH);
  4580.         SetScrollPos (ghTTYWnd, SB_VERT, (int) 0, TRUE);
  4581.         gpTTYInfo->scrollPos = 0;
  4582.         gpTTYInfo->scrollScale = 1.0;
  4583.     }
  4584.     gpTTYInfo->scrollRange = (int)max;
  4585.     }
  4586. }
  4587.  
  4588.  
  4589.  
  4590. /*
  4591.  * Set the current scroll position.
  4592.  */
  4593. void
  4594. mswin_setscrollpos (long pos)
  4595. {
  4596.     int        ipos;
  4597.     
  4598.     if (pos != gpTTYInfo->scrollPos) {
  4599.     ipos = (WORD) ((float)pos / gpTTYInfo->scrollScale);    
  4600.         SetScrollPos (ghTTYWnd, SB_VERT, ipos, TRUE);
  4601.     gpTTYInfo->scrollPos = pos;
  4602.     }
  4603. }
  4604.  
  4605.  
  4606.  
  4607. /*
  4608.  * retreive the current scroll postion.
  4609.  */
  4610. long
  4611. mswin_getscrollpos (void)
  4612. {
  4613.    return ((long)((float)GetScrollPos (ghTTYWnd, SB_VERT) 
  4614.        * gpTTYInfo->scrollScale));
  4615. }
  4616.  
  4617.  
  4618.  
  4619. /*
  4620.  * retreive the latest scroll to position.
  4621.  */
  4622. long
  4623. mswin_getscrollto (void)
  4624. {
  4625.    return (gpTTYInfo->scrollTo);
  4626. }
  4627.  
  4628.  
  4629.  
  4630. /*
  4631.  * install function to deal with LINEDOWN events
  4632.  */
  4633. void
  4634. mswin_setscrollcallback (scroll_t cbfunc)
  4635. {
  4636.     gScrollCallback = cbfunc;
  4637. }
  4638.  
  4639.  
  4640.  
  4641.  
  4642. /*
  4643.  * Set the printer font
  4644.  */
  4645. int        
  4646. mswin_setprintfont (char *fontName, char *fontSize, char *fontStyle)
  4647. {
  4648.     /* Require a font name to set font info. */
  4649.     if (fontName != NULL && *fontName != '\0' && 
  4650.         strlen (fontName) <= LF_FACESIZE - 1) {
  4651.         
  4652.     strncpy (gPrintFontName, fontName, LF_FACESIZE);
  4653.     gPrintFontName[LF_FACESIZE] = 0;
  4654.     strncpy (gPrintFontStyle, fontStyle, 63);
  4655.     gPrintFontStyle[63] = 0;
  4656.     _strlwr (gPrintFontStyle);    /* Lower case font style. */
  4657.     gPrintFontSize = 12;
  4658.     if (ScanInt (fontSize, FONT_MIN_SIZE, FONT_MAX_SIZE, &gPrintFontSize))
  4659.         gPrintFontSize = abs (gPrintFontSize);
  4660.     gPrintFontSameAs = FALSE;
  4661.     }
  4662.     else {
  4663.     gPrintFontName[0] = '\0';
  4664.     gPrintFontSameAs = TRUE;
  4665.     }
  4666. }
  4667.  
  4668.  
  4669.  
  4670.  
  4671. int
  4672. mswin_getprintfont (char *fontName, char *fontSize, char *fontStyle)
  4673. {
  4674.     if (gPrintFontName[0] == '\0' || gPrintFontSameAs) {
  4675.     if (fontName != NULL) 
  4676.         *fontName = '\0';
  4677.     if (fontSize != NULL) 
  4678.         *fontSize = '\0';
  4679.     if (fontStyle != NULL) 
  4680.         *fontName = '\0';
  4681.     }
  4682.     else {
  4683.     if (fontName != NULL) 
  4684.         strcpy (fontName, gPrintFontName);
  4685.     if (fontSize != NULL) 
  4686.         sprintf (fontSize, "%d", gPrintFontSize);
  4687.     if (fontStyle != NULL)
  4688.         strcpy (fontStyle, gPrintFontStyle);
  4689.     }
  4690. }
  4691.  
  4692.  
  4693.  
  4694. /*
  4695.  * Set the window help text.  Add or delete the Help menu item as needed.
  4696.  */
  4697. int
  4698. mswin_sethelptext (char *title, char *pHelpText, size_t len, char **pHelpLines)
  4699. {
  4700.     HMENU        hMenu;
  4701.     BOOL        brc;
  4702.     int            count;
  4703.     
  4704.     /*
  4705.      * Remeber new values. 
  4706.      */
  4707.     gpHelpTitle = title;
  4708.     gpHelpText = pHelpText;
  4709.     gpHelpLen = len;
  4710.     gpHelpLines = pHelpLines;
  4711.  
  4712.     /*
  4713.      * Find menu.
  4714.      */
  4715.     hMenu = GetMenu (ghTTYWnd);
  4716.     if (hMenu == NULL) 
  4717.     return (1);
  4718.     count = GetMenuItemCount (hMenu);
  4719.     if (count == -1) 
  4720.     return (1);
  4721.     
  4722.     hMenu = GetSubMenu (hMenu, count - 1);
  4723.     if (hMenu == NULL) 
  4724.     return (1);
  4725.     
  4726.     /*
  4727.      * Insert or delete.
  4728.      */
  4729.     if (gpHelpText == NULL && gpHelpLines == NULL) {
  4730.     if (gfHelpMenu) {
  4731.         brc = DeleteMenu (hMenu, IDM_HELP, MF_BYCOMMAND);
  4732.         DrawMenuBar (ghTTYWnd);
  4733.     }
  4734.     gfHelpMenu = FALSE;
  4735.     }
  4736.     else {
  4737.     if (!gfHelpMenu) {
  4738.         brc = InsertMenu (hMenu, 0, MF_BYPOSITION | MF_STRING, IDM_HELP, 
  4739.             "General Help");
  4740.         DrawMenuBar (ghTTYWnd);
  4741.     }
  4742.     gfHelpMenu = TRUE;
  4743.     }
  4744.     return (0);
  4745. }
  4746.     
  4747.  
  4748.  
  4749. /*
  4750.  * Set the text displayed when someone tries to close the application 
  4751.  * the wrong way.
  4752.  */
  4753. int
  4754. mswin_setclosetext (char *pCloseText)
  4755. {
  4756.     gpCloseText = pCloseText;
  4757. }
  4758.  
  4759.  
  4760.  
  4761.  
  4762.  
  4763.  
  4764. /*
  4765.  * Called when upper layer is in a busy loop.  Allows us to yeild to
  4766.  * Windows and perhaps process some events.  Does not yeild control
  4767.  * to other applications.
  4768.  */
  4769. int
  4770. mswin_yeild (void)
  4771. {
  4772.     MSG        msg;
  4773.     DWORD    start;
  4774.     int        didmsg = FALSE;
  4775.     
  4776.     if (gScrolling)
  4777.     return (TRUE);
  4778.     
  4779.     start = GetTickCount ();
  4780. #ifdef CDEBUG
  4781.     if (mswin_debug > 16) 
  4782.     fprintf (mswin_debugfile, "mswin_yeild:: Entered\n");
  4783. #endif
  4784.     if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
  4785.     if (gpTTYInfo->hAccel == NULL || 
  4786.         !TranslateAccelerator (ghTTYWnd, gpTTYInfo->hAccel, &msg)) {
  4787.         TranslateMessage (&msg);
  4788.         DispatchMessage (&msg);
  4789.         didmsg = TRUE;
  4790.     }
  4791.     }
  4792. #ifdef CDEBUG
  4793.     if (mswin_debug > 16) 
  4794.     fprintf (mswin_debugfile, "mswin_yeild::  Delay %ld msec\n",
  4795.         GetTickCount () - start);
  4796. #endif
  4797.     return (didmsg);
  4798. }
  4799.  
  4800.  
  4801.  
  4802.  
  4803.  
  4804. /*
  4805.  *    Called to see if we can process input. 
  4806.  *    We can't process input when we are in a scrolling mode.
  4807.  */
  4808. int
  4809. mswin_caninput ()
  4810. {
  4811.     return (!gScrolling && !gMouseTracking);
  4812. }
  4813.  
  4814.  
  4815.  
  4816.  
  4817. /*
  4818.  *    Called to see if there is a character available.
  4819.  */
  4820. int
  4821. mswin_charavail (void)
  4822. {
  4823.     MSG        msg;
  4824.     BOOL    ca, pa, ma;
  4825.     DWORD    start;
  4826.     
  4827.     if (gScrolling)
  4828.     return (FALSE);
  4829.  
  4830.     mswin_setcursor (MSWIN_CURSOR_ARROW);
  4831.  
  4832.     /*
  4833.      * If there are no windows messages waiting for this app, GetMessage
  4834.      * can take a long time.  So before calling GetMessage check if
  4835.      * there is anything I should be doing.  If there is, then only
  4836.      * call PeekMessage.
  4837.      * BUT!  Don't let too much time elapse between calls to GetMessage
  4838.      * or we'll shut out other windows.
  4839.      */
  4840.     ca = CQAvailable ();
  4841.     pa = EditPasteAvailable ();
  4842. #ifdef CDEBUG
  4843.     start = GetTickCount ();
  4844.     if (mswin_debug > 16) 
  4845.     fprintf (mswin_debugfile, "mswin_charavail::  Entered, ca %d, pa %d\n",ca,pa);
  4846. #endif
  4847.     if ((ca || pa) && GetTickCount () < gGMLastCall + GM_MAX_TIME) 
  4848.         ma = PeekMessage (&msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE);
  4849.     else {
  4850.         ma = GetMessage (&msg, NULL, 0, 0);
  4851.     gGMLastCall = GetTickCount ();
  4852.     }
  4853.     if (ma) {
  4854.     if (gpTTYInfo->hAccel == NULL || 
  4855.         !TranslateAccelerator (ghTTYWnd, gpTTYInfo->hAccel, &msg)) {
  4856.         TranslateMessage (&msg);
  4857.         DispatchMessage (&msg);
  4858.     }
  4859.     }
  4860. #ifdef CDEBUG
  4861.     if (mswin_debug > 16) 
  4862.     fprintf (mswin_debugfile, "mswin_charavail::  Delay %ld msec\n",
  4863.         GetTickCount () - start);
  4864. #endif
  4865.  
  4866.     return (pa || ca || CQAvailable ());
  4867. }
  4868.  
  4869.  
  4870.  
  4871.     
  4872.  
  4873. /*
  4874.  *    Call to get next character.  Dispatch one message.
  4875.  */
  4876. int
  4877. mswin_getc (void)
  4878. {
  4879.     BOOL    ca, pa, ma;
  4880.     MSG        msg;
  4881.     DWORD    start;
  4882.     
  4883.     if (gScrolling)
  4884.     return (MSWIN_KEY_NODATA);
  4885.  
  4886.     mswin_setcursor (MSWIN_CURSOR_ARROW);
  4887.  
  4888.     mswin_flush();
  4889.  
  4890.  
  4891.     /*
  4892.      * If there are no windows messages waiting for this app, GetMessage
  4893.      * can take a long time.  So before calling GetMessage check if
  4894.      * there is anything I should be doing.  If there is, then only
  4895.      * call PeekMessage.
  4896.      */
  4897.     ca = CQAvailable ();
  4898.     pa = EditPasteAvailable ();
  4899. #ifdef CDEBUG
  4900.     if (mswin_debug > 16) {
  4901.     start = GetTickCount ();
  4902.     fprintf (mswin_debugfile, "mswin_getc::  Entered, ca %d pa %d\n", ca, pa);
  4903.     }
  4904. #endif
  4905.     if ((ca || pa) && GetTickCount () < gGMLastCall + GM_MAX_TIME) 
  4906.         ma = PeekMessage (&msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE);
  4907.     else {
  4908.         ma = GetMessage (&msg, NULL, 0, 0);
  4909.     gGMLastCall = GetTickCount ();
  4910.     }
  4911.     if (ma) {
  4912.     if (gpTTYInfo->hAccel == NULL || 
  4913.         !TranslateAccelerator (ghTTYWnd, gpTTYInfo->hAccel, &msg)) {
  4914.         TranslateMessage (&msg);
  4915.         DispatchMessage (&msg);
  4916.     }
  4917.     }
  4918. #ifdef CDEBUG
  4919.     if (mswin_debug > 16) 
  4920.     fprintf (mswin_debugfile, "mswin_getc::  Delay %ld msec\n",
  4921.         GetTickCount () - start);
  4922. #endif
  4923.  
  4924.  
  4925.     if (pa) {
  4926.     SelClear ();
  4927.     return (EditPasteGet ());
  4928.     }
  4929.     if (ca || CQAvailable ()) {
  4930.     SelClear();
  4931.     return (CQGet ());
  4932.     }
  4933.     return (MSWIN_KEY_NODATA);
  4934. }
  4935.  
  4936.  
  4937.  
  4938.  
  4939. /*
  4940.  *    Like mswin_getc, but don't yeild control.
  4941.  */
  4942. int
  4943. mswin_getc_fast (void)
  4944. {
  4945.     MSG        msg;
  4946.     
  4947.     mswin_setcursor (MSWIN_CURSOR_ARROW);
  4948.     
  4949.     if (EditPasteAvailable ()) {
  4950.     SelClear ();
  4951.     return (EditPasteGet ());
  4952.     }
  4953.     if (CQAvailable ()) {
  4954.     SelClear ();
  4955.     return (CQGet ());
  4956.     }
  4957.     return (MSWIN_KEY_NODATA);
  4958. }
  4959.  
  4960.  
  4961.  
  4962.  
  4963.  
  4964.  
  4965.  
  4966. /*
  4967.  * ibmopen - open termnal
  4968.  */
  4969. int
  4970. mswin_open (void)
  4971. {
  4972.     /* This is a no-op.  All of this should have been set up already. */
  4973.     revexist = TRUE;
  4974.     return (0);
  4975. }
  4976.  
  4977.  
  4978. /*
  4979.  * ibmclose - Close terminal
  4980.  */
  4981. int
  4982. mswin_close (void)
  4983. {
  4984.     /* Another no-op. */
  4985.     return (0);
  4986. }
  4987.  
  4988.  
  4989.  
  4990.  
  4991. /*
  4992.  * ibmmove - Move cursor to...
  4993.  */
  4994. int
  4995. mswin_move (int row, int column)
  4996.  
  4997. {
  4998.     FlushWriteAccum ();
  4999.     if (row < 0 || row >= gpTTYInfo->actNRow)
  5000.     return (-1);
  5001.     if (column < 0 || column >= gpTTYInfo->actNColumn)
  5002.     return (-1);
  5003.     gpTTYInfo->nRow = row;
  5004.     gpTTYInfo->nColumn = column;
  5005.     MoveTTYCursor (ghTTYWnd);
  5006.     return (0);
  5007. }
  5008.  
  5009.  
  5010.  
  5011. int
  5012. mswin_getpos (int *row, int *column)
  5013. {
  5014.     FlushWriteAccum ();
  5015.     if (row == NULL || column == NULL)
  5016.     return (-1);
  5017.     *row = gpTTYInfo->nRow;
  5018.     *column = gpTTYInfo->nColumn;
  5019.     return (0);
  5020. }
  5021.  
  5022.  
  5023.  
  5024. int
  5025. mswin_getscreensize (int *row, int *column)
  5026. {
  5027.     if (row == NULL || column == NULL)
  5028.     return (-1);
  5029.     *row = gpTTYInfo->actNRow;
  5030.     *column = gpTTYInfo->actNColumn;
  5031. #ifdef SDEBUG
  5032.     if (mswin_debug >= 5) 
  5033.     fprintf (mswin_debugfile, "mswin_getscreensize::: reported size %d, %d\n",
  5034.         *row, *column);
  5035. #endif
  5036.     return (0);
  5037. }
  5038.  
  5039.  
  5040.  
  5041.  
  5042. int
  5043. mswin_showcursor (int show)
  5044. {
  5045.     int        wasShow;
  5046.     
  5047.     
  5048.     wasShow = (gpTTYInfo->wCursorState & CS_SHOW) != 0;
  5049.     
  5050.     if (show) {
  5051.     
  5052.     /* if the cursor was not already show, show it now. */
  5053.     if (!wasShow) {
  5054.         gpTTYInfo->wCursorState |= CS_SHOW;
  5055.  
  5056.         if (gpTTYInfo->wCursorState == CS_VISIBLE) {
  5057.             CreateCaret (ghTTYWnd, NULL, gpTTYInfo->xChar, 
  5058.                 gpTTYInfo->yChar);
  5059.             ShowCaret (ghTTYWnd);
  5060.         }
  5061.         MoveTTYCursor (ghTTYWnd);
  5062.         }
  5063.     }
  5064.     else {
  5065.     
  5066.     /* If the cursor is shown, hide it. */
  5067.     if (wasShow) {
  5068.         if (gpTTYInfo->wCursorState == CS_VISIBLE) {
  5069.         HideCaret (ghTTYWnd);
  5070.         DestroyCaret();
  5071.         }
  5072.  
  5073.         gpTTYInfo->wCursorState &= ~CS_SHOW;
  5074.     }
  5075.     }
  5076.  
  5077.     return (wasShow);
  5078. }
  5079.  
  5080.  
  5081.  
  5082. int
  5083. mswin_puts (char *str)
  5084. {
  5085.     int            strLen;
  5086.  
  5087.     FlushWriteAccum ();
  5088.     if (str == NULL)
  5089.     return (-1);
  5090.     strLen = strlen (str);
  5091.     if (strLen > 0)
  5092.     WriteTTYText (ghTTYWnd, str, strLen);
  5093.     return (0);
  5094. }
  5095.  
  5096.  
  5097.  
  5098. int
  5099. mswin_putblock (char *str, int strLen)
  5100. {
  5101.     FlushWriteAccum ();
  5102.     if (str == NULL)
  5103.     return (-1);
  5104.     if (strLen > 0)
  5105.     WriteTTYText (ghTTYWnd, str, strLen);
  5106.     return (0);
  5107. }
  5108.  
  5109.  
  5110.  
  5111. /*
  5112.  * mswin_putc - put a character at the current position in the
  5113.  *         current colors
  5114.  */
  5115.  
  5116. int
  5117. mswin_putc (int c)
  5118. {
  5119.     BYTE        cc;
  5120.  
  5121.     cc = (char)(c & 0xff);
  5122.  
  5123.     if (cc >= ' ') {
  5124.     /* Not carrage control. */
  5125.     gpTTYInfo->writeAccum[gpTTYInfo->writeAccumCount++] = cc;
  5126.     if (gpTTYInfo->writeAccumCount == WRITE_ACCUM_SIZE)
  5127.         FlushWriteAccum ();
  5128.     }
  5129.     else {
  5130.     /* Carrage control.  Need to flush write accumulator and
  5131.      * write this char. */
  5132.     FlushWriteAccum ();
  5133.     WriteTTYBlock (ghTTYWnd, &cc, 1);
  5134.     }
  5135.     return (0);
  5136. }
  5137.  
  5138.  
  5139.  
  5140. /* 
  5141.  * ibmoutc - output a single character with the right attributes, but
  5142.  *           don't advance the cursor
  5143.  */
  5144. int
  5145. mswin_outc (char c)
  5146. {
  5147.     RECT    rect;
  5148.     long    offset;
  5149.     
  5150.     FlushWriteAccum ();
  5151.     
  5152.     switch (c) {
  5153.     case ASCII_BEL:
  5154.     MessageBeep (0);
  5155.     break;
  5156.     
  5157.     case ASCII_BS:
  5158.     case ASCII_CR:
  5159.     case ASCII_LF:
  5160.     /* Do nothing for these screen motion characters. */
  5161.     break;
  5162.     
  5163.     
  5164.     default:
  5165.     /* Paint character to screen. */
  5166.     offset = (gpTTYInfo->nRow * gpTTYInfo->actNColumn) + gpTTYInfo->nColumn;
  5167.     *(gpTTYInfo->pScreen + offset) = c;
  5168.     *(gpTTYInfo->pAttrib + offset) = gpTTYInfo->curAttrib;
  5169.     
  5170.     /* Invalidate rectange covering singel character. */
  5171.     rect.left = (gpTTYInfo->nColumn * gpTTYInfo->xChar) +
  5172.         gpTTYInfo->xOffset;
  5173.     rect.right = rect.left + gpTTYInfo->xChar;
  5174.     rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) + 
  5175.         gpTTYInfo->yOffset;
  5176.     rect.bottom = rect.top + gpTTYInfo->yChar;
  5177.     gpTTYInfo->screenDirty = TRUE;
  5178.     InvalidateRect (ghTTYWnd, &rect, FALSE);
  5179.     break;
  5180.     }
  5181.     return (0);
  5182. }
  5183.  
  5184.  
  5185.  
  5186. /*
  5187.  * mswin_delchar - delete character at cursor.  Shift end of line left.
  5188.  *    Cursor stays in position.
  5189.  */
  5190. int
  5191. mswin_delchar (void)
  5192. {
  5193.     CHAR    *cStart;
  5194.     CharAttrib    *aStart;
  5195.     long    length;
  5196.     RECT    rect;
  5197.     
  5198.     FlushWriteAccum ();
  5199.     
  5200.     /* From position right of cursor to end of line. */
  5201.     length = gpTTYInfo->actNColumn - (gpTTYInfo->nColumn + 1);
  5202.  
  5203.     /* Shift end of line. */
  5204.     if (length > 0) {
  5205.         cStart = gpTTYInfo->pScreen + (gpTTYInfo->nRow *gpTTYInfo->actNColumn)
  5206.                 + gpTTYInfo->nColumn;
  5207.     memmove (cStart, cStart+1, (size_t) length);
  5208.         aStart = gpTTYInfo->pAttrib + (gpTTYInfo->nRow *gpTTYInfo->actNColumn)
  5209.             + gpTTYInfo->nColumn;
  5210.         memmove (aStart, aStart + 1, (size_t) length);
  5211.     }
  5212.     
  5213.     /* Clear last char in line. */
  5214.     *(cStart + length) = ' ';
  5215.     *(aStart + length) = CHAR_ATTR_NORM;
  5216.  
  5217.     /* Invalidate from cursor to end of line. */
  5218.     rect.left = (gpTTYInfo->nColumn * gpTTYInfo->xChar) + gpTTYInfo->xOffset;
  5219.     rect.right = gpTTYInfo->xSize;
  5220.     rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) + gpTTYInfo->yOffset;
  5221.     rect.bottom = rect.top + gpTTYInfo->yChar;
  5222.     gpTTYInfo->screenDirty = TRUE;
  5223.     InvalidateRect (ghTTYWnd, &rect, FALSE);
  5224.  
  5225.     return (0);
  5226. }
  5227.  
  5228.  
  5229.  
  5230. /*
  5231.  * mswin_inschar - insert character in current position.  Shift line
  5232.  *    to right and drop last char on line. 
  5233.  *    Cursor advances one 
  5234.  */
  5235. int
  5236. mswin_inschar (int c)
  5237. {
  5238.     CHAR    *cStart;
  5239.     CharAttrib    *aStart;
  5240.     long    length;
  5241.     RECT    rect;
  5242.     
  5243.     FlushWriteAccum ();
  5244.     
  5245.     /* From cursor to end of line - 1
  5246.     length = (gpTTYInfo->actNColumn - gpTTYInfo->nColumn) - 1;
  5247.  
  5248.     /* Shift end of line. */
  5249.     if (length > 0) {
  5250.         cStart = gpTTYInfo->pScreen + (gpTTYInfo->nRow *gpTTYInfo->actNColumn)
  5251.                 + gpTTYInfo->nColumn;
  5252.     memmove (cStart+1, cStart, (size_t) length);
  5253.         aStart = gpTTYInfo->pAttrib + (gpTTYInfo->nRow *gpTTYInfo->actNColumn)
  5254.             + gpTTYInfo->nColumn;
  5255.         memmove (aStart+1, aStart, (size_t) length);
  5256.     }
  5257.     
  5258.     /* Insert new char. */
  5259.     *(cStart + length) = (char)(c & 0x00ff);
  5260.     *(aStart + length) = gpTTYInfo->curAttrib;
  5261.  
  5262.     /* Invalidate from cursor to end of line. */
  5263.     rect.left = (gpTTYInfo->nColumn * gpTTYInfo->xChar) + gpTTYInfo->xOffset;
  5264.     rect.right = gpTTYInfo->xSize;
  5265.     rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) + gpTTYInfo->yOffset;
  5266.     rect.bottom = rect.top + gpTTYInfo->yChar;
  5267.     gpTTYInfo->screenDirty = TRUE;
  5268.     InvalidateRect (ghTTYWnd, &rect, FALSE);
  5269.     
  5270.     /* move cursor forward one space. */
  5271.     if (gpTTYInfo->nColumn < gpTTYInfo->actNColumn - 1) {
  5272.     ++gpTTYInfo->nColumn;
  5273.     MoveTTYCursor (ghTTYWnd);
  5274.     }
  5275.  
  5276.     return (0);
  5277. }
  5278.  
  5279.  
  5280.  
  5281. /*
  5282.  * ibmrev - change reverse video state
  5283.  */
  5284. int
  5285. mswin_rev (int state)
  5286. {
  5287.     int        curState;
  5288.     
  5289.     curState = (gpTTYInfo->curAttrib & CHAR_ATTR_REV);
  5290.     if ((state && !curState) || (!state && curState)) {
  5291.     FlushWriteAccum ();
  5292.     if (state) 
  5293.         gpTTYInfo->curAttrib |= CHAR_ATTR_REV;
  5294.     else
  5295.         gpTTYInfo->curAttrib &= ~CHAR_ATTR_REV;
  5296.     }
  5297.     return (0);
  5298. }
  5299.     
  5300.  
  5301.  
  5302. /*
  5303.  * Get current reverse video state. 
  5304.  */
  5305. int
  5306. mswin_getrevstate (void)
  5307. {
  5308.     return ((gpTTYInfo->curAttrib & CHAR_ATTR_REV) != 0);
  5309. }
  5310.  
  5311.  
  5312.  
  5313. /*
  5314.  * ibmeeol - erase to the end of the line
  5315.  */
  5316. int
  5317. mswin_eeol (void)
  5318. {
  5319.     CHAR    *cStart;
  5320.     CharAttrib    *aStart;
  5321.     long    length;
  5322.     RECT    rect;
  5323.     
  5324.     FlushWriteAccum ();
  5325.     
  5326.     /* From current position to end of line. */
  5327.     length = gpTTYInfo->actNColumn - gpTTYInfo->nColumn;        
  5328.  
  5329.     cStart = gpTTYInfo->pScreen + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
  5330.             + gpTTYInfo->nColumn;
  5331.     memset (cStart, ' ', (size_t) length);
  5332.     
  5333.     aStart = gpTTYInfo->pAttrib + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
  5334.             + gpTTYInfo->nColumn;
  5335.     memset (aStart, CHAR_ATTR_NORM, (size_t) length);
  5336.  
  5337.     rect.left = (gpTTYInfo->nColumn * gpTTYInfo->xChar) + 
  5338.         gpTTYInfo->xOffset;
  5339.     rect.right = gpTTYInfo->xSize;
  5340.     rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) + 
  5341.         gpTTYInfo->yOffset;
  5342.     rect.bottom = rect.top + gpTTYInfo->yChar;
  5343.     gpTTYInfo->screenDirty = TRUE;
  5344.     InvalidateRect (ghTTYWnd, &rect, FALSE);
  5345.  
  5346.     return (0);
  5347. }
  5348.  
  5349.  
  5350.  
  5351. /*
  5352.  * ibmeeop - clear from cursor to end of page
  5353.  */
  5354. int
  5355. mswin_eeop (void)
  5356. {
  5357.     CHAR    *cStart;
  5358.     CharAttrib    *aStart;
  5359.     long    length;
  5360.     RECT    rect;
  5361.     
  5362.     FlushWriteAccum ();
  5363.     /* From current position to end of screen. */
  5364.  
  5365.     cStart = gpTTYInfo->pScreen + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
  5366.             + gpTTYInfo->nColumn;
  5367.     length = (gpTTYInfo->pScreen + (gpTTYInfo->actNColumn * gpTTYInfo->actNRow))
  5368.             - cStart;
  5369.     memset (cStart, ' ', (size_t) length);
  5370.     
  5371.     aStart = gpTTYInfo->pAttrib + (gpTTYInfo->nRow * gpTTYInfo->actNColumn)
  5372.             + gpTTYInfo->nColumn;
  5373.     memset (aStart, CHAR_ATTR_NORM, (size_t) length);
  5374.  
  5375.     
  5376.     /* Invalidate a rectangle that includes all of the current line down
  5377.      * to the bottom of the window. */
  5378.     rect.left = 0;
  5379.     rect.right = gpTTYInfo->xSize;
  5380.     rect.top = (gpTTYInfo->nRow * gpTTYInfo->yChar) + 
  5381.         gpTTYInfo->yOffset;
  5382.     rect.bottom = gpTTYInfo->ySize;
  5383.     gpTTYInfo->screenDirty = TRUE;
  5384.     InvalidateRect (ghTTYWnd, &rect, FALSE);
  5385.  
  5386.     return (0);
  5387. }
  5388.  
  5389.  
  5390.  
  5391. /*
  5392.  * ibmbeep - system beep...
  5393.  */
  5394. int
  5395. mswin_beep (void)
  5396. {
  5397.     MessageBeep (MB_OK);
  5398.     return (0);
  5399. }
  5400.  
  5401.  
  5402. /*
  5403.  * pause - wait in function for specified number of seconds.
  5404.  */
  5405. int
  5406. mswin_pause (int seconds)
  5407. {
  5408.     DWORD    stoptime;
  5409.     
  5410.     stoptime = GetTickCount () + (DWORD) seconds * 1000;
  5411.     while (stoptime > GetTickCount ()) 
  5412.     mswin_yeild ();
  5413. }
  5414.     
  5415.  
  5416.  
  5417. /*
  5418.  * ibmflush - Flush output to screen.
  5419.  *
  5420.  */
  5421. int
  5422. mswin_flush (void)
  5423. {
  5424.  
  5425.     /*
  5426.      * Flush cached changes, then update the window.
  5427.      */
  5428.     FlushWriteAccum ();
  5429.     UpdateWindow (ghTTYWnd);
  5430.     
  5431.     return (0);
  5432. }
  5433.  
  5434.  
  5435.  
  5436.  
  5437. /*
  5438.  * A replacement for fflush
  5439.  * relies on #define fflush mswin_fflush
  5440.  */
  5441. #undef fflush
  5442. int
  5443. mswin_fflush (FILE *f)
  5444. {
  5445.     if (f == stdout) {
  5446.     mswin_flush();
  5447.     }
  5448.     else
  5449.     fflush (f);
  5450. }
  5451.  
  5452.  
  5453.  
  5454.  
  5455. /*
  5456.  * Set the cursor
  5457.  */
  5458. void
  5459. mswin_setcursor (int newcursor)
  5460. {
  5461.     HCURSOR hNewCursor;
  5462.  
  5463.  
  5464.     /* There is either the busy currsor or the arrow cursor. */
  5465.     if (newcursor == MSWIN_CURSOR_BUSY) 
  5466.         hNewCursor = ghCursorBusy;
  5467.     else
  5468.     hNewCursor = ghCursorArrow;
  5469.  
  5470.     /* If new cursor requested, select it. */
  5471.     if (hNewCursor != ghCursorCurrent) {
  5472.     ghCursorCurrent = hNewCursor;
  5473.     SetCursor (ghCursorCurrent);
  5474.     }
  5475. }
  5476.     
  5477.  
  5478.  
  5479.  
  5480.  
  5481.  
  5482. /*
  5483.  * Print to the screen.
  5484.  */
  5485. int
  5486. printf (const char *fmt, ...)
  5487. {
  5488.     va_list    marker;
  5489.     int        strLen;
  5490.     
  5491.     va_start (marker, fmt);
  5492.     _vsnprintf (TempBuf, MAXLEN_TEMPSTR, fmt, marker);
  5493.     
  5494.     FlushWriteAccum ();
  5495.     strLen = strlen (TempBuf);
  5496.     if (strLen > 0) {
  5497.         if (TempBuf[strLen-1] == ASCII_LF) {
  5498.         TempBuf[strLen-1] == ASCII_CR;
  5499.         TempBuf[strLen] == ASCII_LF;
  5500.         TempBuf[++strLen] = '\0';
  5501.         }
  5502.     WriteTTYBlock (ghTTYWnd, TempBuf, strLen);
  5503.     }
  5504.     return (1);
  5505. }
  5506.  
  5507.  
  5508.  
  5509.  
  5510. /*
  5511.  * Display message in windows dialog box. 
  5512.  */
  5513. int
  5514. mswin_messagebox (char *msg)
  5515. {
  5516.     MessageBox (NULL, msg, gszAppName, MB_OK | MB_ICONSTOP);
  5517. }
  5518.  
  5519.  
  5520.  
  5521.  
  5522. /*
  5523.  * Signals whether or not Paste should be turned on in the
  5524.  * menu bar.
  5525.  */
  5526. int
  5527. mswin_allowpaste (int on)
  5528. {
  5529.     HMENU        hMenu;
  5530.     
  5531.     hMenu = GetMenu (ghTTYWnd);
  5532.     gPasteEnabled = on;
  5533.     if(!IsClipboardFormatAvailable (CF_TEXT) || on == MSWIN_PASTE_DISABLE)
  5534.       EnableMenuItem (hMenu, IDM_EDIT_PASTE, (MF_BYCOMMAND | MF_GRAYED));
  5535.     else
  5536.       EnableMenuItem (hMenu, IDM_EDIT_PASTE, (MF_BYCOMMAND | MF_ENABLED));
  5537.  
  5538. }
  5539.  
  5540.  
  5541.  
  5542. /*
  5543.  * Signals whether or not Copy/Cut should be turned on in the
  5544.  * menu bar.
  5545.  */
  5546. int
  5547. mswin_allowcopy (getc_t copyfunc)
  5548. {
  5549.     gCopyCutFunction = copyfunc;
  5550.     gAllowCopy = (copyfunc != NULL);
  5551. }
  5552.  
  5553.  
  5554.  
  5555. /*
  5556.  * Signals whether or not Copy/Cut should be turned on in the
  5557.  * menu bar.
  5558.  */
  5559. int
  5560. mswin_allowcopycut (getc_t copyfunc)
  5561. {
  5562.     gCopyCutFunction = copyfunc;
  5563.     gAllowCopy = gAllowCut = (copyfunc != NULL);
  5564. }
  5565.  
  5566.  
  5567.  
  5568. /*
  5569.  * Signals if the upper layer wants to track the mouse.
  5570.  */
  5571. int
  5572. mswin_allowmousetrack (int b)
  5573. {
  5574.     gAllowMouseTrack = b;
  5575.     if (b) 
  5576.     SelClear ();
  5577.     MyTimerSet ();
  5578. }
  5579.  
  5580.  
  5581.  
  5582. int
  5583. mswin_newmailicon (void)
  5584. {
  5585.     if (gpTTYInfo->fMinimized) {
  5586.     gpTTYInfo->fNewMailIcon = TRUE;
  5587.     gpTTYInfo->screenDirty = TRUE;
  5588.     gpTTYInfo->eraseScreen = TRUE;
  5589.     InvalidateRect (ghTTYWnd, NULL, FALSE);
  5590.     }
  5591. }
  5592.  
  5593.  
  5594.  
  5595. /*---------------------------------------------------------------------------
  5596.  *
  5597.  * Client level menu item stuff.
  5598.  *
  5599.  * These are menu items that activate commands in the "client" program.
  5600.  * Generally, the client calls us to tell us which menu items are active
  5601.  * and what key stroke they generate.  When such an item is selected it's
  5602.  * key stroke is injected into the character queue as if it was typed by
  5603.  * the user.
  5604.  *
  5605.  *-------------------------------------------------------------------------*/
  5606.  
  5607. /*
  5608.  * Clear active status of all "menu items".
  5609.  */
  5610. void
  5611. mswin_menuitemclear (void)
  5612. {
  5613.     int            i;
  5614.     HWND        hWnd;
  5615.     
  5616.  
  5617.     for (i = 0; i < KS_COUNT; ++i) {
  5618.     gpTTYInfo->menuItems[i].miActive = FALSE;
  5619.     if (gpTTYInfo->toolBarSize > 0) {
  5620.         hWnd = GetDlgItem(gpTTYInfo->hTBWnd, i + KS_RANGESTART);
  5621.         if (hWnd != NULL)
  5622.         EnableWindow(hWnd, FALSE);
  5623.     }
  5624.     }
  5625.     gpTTYInfo->menuItemsCurrent = FALSE;
  5626. }
  5627.  
  5628.  
  5629. /*
  5630.  * Add an item to the cmdmenu
  5631.  */
  5632. void
  5633. mswin_menuitemadd (int key, char *label, int menuitem, int flags)
  5634. {
  5635.     int            i;
  5636.     HWND        hWnd;
  5637.     
  5638.     if (menuitem >= KS_RANGESTART && menuitem <= KS_RANGEEND) {
  5639.      
  5640.     gpTTYInfo->menuItemsCurrent = FALSE;
  5641.     
  5642.     i = menuitem - KS_RANGESTART;
  5643.     gpTTYInfo->menuItems[i].miActive = TRUE;
  5644.     gpTTYInfo->menuItems[i].miKey = key;
  5645.  
  5646.     if (gpTTYInfo->toolBarSize > 0) {
  5647.         hWnd = GetDlgItem(gpTTYInfo->hTBWnd, menuitem);
  5648.         if (hWnd != NULL)
  5649.         EnableWindow(hWnd, TRUE);
  5650.     }
  5651.     }
  5652. }
  5653.  
  5654.  
  5655.  
  5656. /*
  5657.  * Called when a menu command arrives with an unknown ID.  If it is
  5658.  * within the range of the additional menu items, insert the
  5659.  * corresponding character into the char input queue.
  5660.  */
  5661. void
  5662. ProcessMenuItem (HWND hWnd, WPARAM wParam) 
  5663. {
  5664.     PTTYINFO        pTTYInfo;
  5665.     int            i;
  5666.  
  5667.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  5668.     if (pTTYInfo == NULL)
  5669.     return;
  5670.  
  5671.     
  5672.     if (wParam >= KS_RANGESTART && wParam <= KS_RANGEEND) {
  5673.     i = wParam - KS_RANGESTART;
  5674.     if (pTTYInfo->menuItems[i].miActive) 
  5675.         CQAdd (pTTYInfo->menuItems[i].miKey, 0);
  5676.     }
  5677. }
  5678.  
  5679.  
  5680.  
  5681.  
  5682.  
  5683. /*
  5684.  * Called to set a new menu.
  5685.  */
  5686. int
  5687. mswin_setwindowmenu (int menu)
  5688. {
  5689.     int        oldmenu;
  5690.     HMENU    holdmenu;
  5691.     HMENU    hmenu;
  5692.     
  5693.     
  5694.     oldmenu = gpTTYInfo->curWinMenu;
  5695.     holdmenu = GetMenu (ghTTYWnd);
  5696.     if (gpTTYInfo->curWinMenu != menu) {
  5697.     
  5698.     hmenu = LoadMenu (ghInstance, MAKEINTRESOURCE (menu));
  5699.     if (hmenu != NULL) {
  5700.         if (SetMenu (ghTTYWnd, hmenu) != 0) {
  5701.             DestroyMenu (holdmenu);
  5702.         gfHelpMenu = FALSE;
  5703.         gpTTYInfo->curWinMenu = menu;
  5704.         if (gpHelpText != NULL || gpHelpLines != NULL) 
  5705.             mswin_sethelptext (gpHelpTitle, gpHelpText, gpHelpLen,
  5706.                     gpHelpLines);
  5707.         }
  5708.     }
  5709.     
  5710.     TBSwap (ghTTYWnd,
  5711.         menu == MENU_DEFAULT ? IDD_TOOLBAR : IDD_COMPOSER_TB);
  5712.     }
  5713.     return (oldmenu);
  5714. }
  5715.  
  5716.  
  5717.  
  5718.  
  5719.  
  5720.  
  5721. /*---------------------------------------------------------------------------
  5722.  *
  5723.  * Printing stuff
  5724.  *
  5725.  *-------------------------------------------------------------------------*/
  5726.  
  5727. /*
  5728.  * Printing globals
  5729.  */
  5730. LOCAL HDC    P_PrintDC;    /* Printer device context. */
  5731. LOCAL int    P_PageRows;    /* Number of rows we put on a page. */
  5732. LOCAL int    P_PageColumns;    /* Number of columns we put on a page. */
  5733. LOCAL int    P_RowHeight;    /* Hight of a row in printer pixels. */
  5734. LOCAL int    P_CurRow;    /* Current row, starting at zero */
  5735. LOCAL int    P_CurCol;    /* Current col, starting at zero. */
  5736. LOCAL int    P_TopOffset;    /* Top Margin offset, in pixels. */
  5737. LOCAL int    P_LeftOffset;    /* Top Margin offset, in pixels. */
  5738. LOCAL HFONT    P_hFont;    /* Handle to printing font. */
  5739. char        *P_LineText;    /* Pointer to line buffer. */
  5740.  
  5741.  
  5742.  
  5743.  
  5744. /*
  5745.  * Define the margin as number of lines at top and bottom of page. 
  5746.  * (might be better to define as a percent of verticle page size)
  5747.  */
  5748. #define VERTICLE_MARGIN        3    /* lines at top and bottom of page. */
  5749. #define HORIZONTAL_MARGIN    1    /* margine at left & right in chars */
  5750.  
  5751. /*
  5752.  * Several errors that can be reported. 
  5753.  */
  5754. #define PE_DIALOG_FAILED    1
  5755. #define PE_USER_CANCEL        2
  5756. #define PE_CANT_START_DOC    3
  5757. #define PE_OUT_OF_MEMORY    4
  5758. #define PE_GENERAL_ERROR    5
  5759. #define PE_OUT_OF_DISK        6
  5760. #define PE_PRINTER_NOT_FOUND    7
  5761. #define PE_PINE_INTERNAL    8
  5762. #define PE_FONT_FAILED        9
  5763.  
  5764.  
  5765. LOCAL struct pe_error_message {
  5766.     int        error_code;
  5767.     char        *error_message;
  5768.  } P_ErrorMessages[] = {
  5769.     { PE_DIALOG_FAILED, "Print Dialog Failed"},
  5770.         { PE_USER_CANCEL, "User canceled" },
  5771.         { PE_CANT_START_DOC,    "Can't start document" },
  5772.     { PE_OUT_OF_MEMORY,    "Out of memory" },
  5773.     { PE_OUT_OF_DISK,    "Out of disk space" },
  5774.     { PE_PRINTER_NOT_FOUND,    "Printer not found" },
  5775.     { PE_PINE_INTERNAL,    "Pine internal error" },
  5776.     { PE_FONT_FAILED,    "Failed to create font" },
  5777.     { 0, NULL }};
  5778.  
  5779.  
  5780.  
  5781. /*
  5782.  * Send text in the line buffer to the printer.  
  5783.  * Advance to next page if necessary.
  5784.  */
  5785. LOCAL int
  5786. _print_send_line (void)
  5787. {
  5788.     int        status;
  5789.     
  5790.     status = 0;
  5791.     if (P_CurCol > 0) 
  5792.     TextOut (P_PrintDC, P_LeftOffset, 
  5793.                 P_TopOffset + (P_CurRow * P_RowHeight), 
  5794.         P_LineText, P_CurCol);
  5795.     P_CurCol = 0;
  5796.     if (++P_CurRow >= P_PageRows) 
  5797.     status = _print_send_page ();
  5798.     
  5799.     return (status);
  5800. }
  5801.  
  5802.     
  5803.  
  5804. /*
  5805.  * Advance one page. 
  5806.  */
  5807. int
  5808. _print_send_page ()
  5809. {
  5810.     int        status;
  5811.     
  5812.     
  5813.     status = EndPage (P_PrintDC);
  5814.     if (status < 0)
  5815.     goto PrintError;
  5816.     P_CurRow = 0;
  5817.     StartPage (P_PrintDC);
  5818.     SelectObject (P_PrintDC, P_hFont);
  5819.     return (0);
  5820.     
  5821.     
  5822. PrintError:
  5823.     switch (status) {
  5824.     case SP_USERABORT:    return (PE_USER_CANCEL);
  5825.     case SP_OUTOFDISK:  return (PE_OUT_OF_DISK);
  5826.     case SP_OUTOFMEMORY:  return (PE_OUT_OF_MEMORY);
  5827.     default:
  5828.     case SP_ERROR:    return (PE_GENERAL_ERROR);
  5829.     }
  5830. }
  5831.  
  5832.  
  5833.  
  5834. /*
  5835.  * Map errors reported to my own error set.
  5836.  */
  5837. int
  5838. _print_map_dlg_error (DWORD error)
  5839. {
  5840.     switch (error) {
  5841.     case 0:                return (PE_USER_CANCEL);
  5842.     case CDERR_MEMALLOCFAILURE:
  5843.     case CDERR_MEMLOCKFAILURE:
  5844.                     return (PE_OUT_OF_MEMORY);
  5845.     case PDERR_PRINTERNOTFOUND:
  5846.     case PDERR_NODEVICES:
  5847.                     return (PE_PRINTER_NOT_FOUND);
  5848.     case CDERR_STRUCTSIZE:
  5849.                     return (PE_PINE_INTERNAL);
  5850.     default:
  5851.                     return (PE_GENERAL_ERROR);
  5852.     }
  5853. }
  5854.     
  5855.  
  5856.  
  5857. /*
  5858.  * Get the printer ready.  Returns ZERO for success, or an error code that
  5859.  * can be passed to mswin_print_error() to get a text message.
  5860.  */
  5861. int
  5862. mswin_print_ready (WINHAND hWnd, char *docDesc)
  5863. {
  5864.     PRINTDLG        pd;
  5865.     DOCINFO        di;
  5866.     TEXTMETRIC        tm;
  5867.     HDC            hDC;
  5868.     int            fontSize;    /* Size in Points. */
  5869.     int            ppi;        /* Pixels per inch in device. */
  5870.     int            xChar;
  5871.     int            status;
  5872.     HFONT        oldFont;
  5873.     LOGFONT        newFont;
  5874.     
  5875.     
  5876.     status = 0;
  5877.     P_PrintDC = NULL;
  5878.  
  5879.     
  5880.     /*
  5881.      * Show print dialog.
  5882.      */
  5883.     pd.lStructSize = sizeof (pd);
  5884.     pd.hwndOwner = (hWnd ? (HWND) hWnd : ghTTYWnd);
  5885.     pd.hDevMode = NULL;
  5886.     pd.hDevNames = NULL;
  5887.     pd.Flags = PD_ALLPAGES | PD_NOSELECTION | PD_NOPAGENUMS | 
  5888.         PD_HIDEPRINTTOFILE | PD_RETURNDC;
  5889.     pd.nCopies = 1;
  5890.     if (PrintDlg (&pd) == 0) 
  5891.     return (_print_map_dlg_error (CommDlgExtendedError()));
  5892.  
  5893.     
  5894.     /*
  5895.      * Returns the device name which we could use to remember what printer 
  5896.      * they selected.  But instead, we just toss them.
  5897.      */
  5898.     if (pd.hDevNames)
  5899.     GlobalFree (pd.hDevNames);
  5900.     if (pd.hDevMode)
  5901.     GlobalFree (pd.hDevMode);
  5902.  
  5903.     /*
  5904.      * Get the device drawing context.
  5905.      * (does PringDlg() ever return success but fail to return a DC?)
  5906.      */
  5907.     if (pd.hDC != NULL) 
  5908.     P_PrintDC = pd.hDC;
  5909.     else {
  5910.         status = PE_DIALOG_FAILED;
  5911.     goto Done;
  5912.     }
  5913.     
  5914.     
  5915.  
  5916.     
  5917.     /*
  5918.      * Start Document
  5919.      */
  5920.     di.cbSize = sizeof (DOCINFO);
  5921.     di.lpszDocName = docDesc;        /* This appears in the print manager*/
  5922.     di.lpszOutput = NULL;        /* Could suply a file name to print
  5923.                        to. */
  5924.     if (StartDoc (P_PrintDC, &di) < 0) {
  5925.     DeleteDC (P_PrintDC);
  5926.     P_PrintDC = NULL;
  5927.     status = PE_CANT_START_DOC;
  5928.     goto Done;
  5929.     }
  5930.     
  5931.     
  5932.     
  5933.     /*
  5934.      * Printer font is either same as window font, or is it's own
  5935.      * font.
  5936.      */
  5937.     if (gPrintFontSameAs) {
  5938.  
  5939.     /*
  5940.      * Get the current font size in points, then create a new font
  5941.      * of same size for printer.  Do the calculation using the actual
  5942.      * screen resolution instead of the logical resolution so that
  5943.      * we get pretty close to the same font size on the printer
  5944.      * as we see on the screen.
  5945.      */
  5946.     hDC = GetDC (ghTTYWnd);            /* Temp screen DC. */
  5947.     ppi = (int) ((float)GetDeviceCaps (hDC, VERTRES) / 
  5948.             ((float) GetDeviceCaps (hDC, VERTSIZE) / 25.3636));
  5949. #ifdef FDEBUG
  5950.     if (mswin_debug >= 8) {
  5951.         fprintf (mswin_debugfile, "mswin_print_ready:  Screen res %d ppi, font height %d pixels\n",
  5952.         ppi, -gpTTYInfo->lfTTYFont.lfHeight);
  5953.         fprintf (mswin_debugfile, "                    Screen height %d pixel, %d mm\n",
  5954.             GetDeviceCaps (hDC, VERTRES), GetDeviceCaps (hDC, VERTSIZE));
  5955.     }
  5956. #endif
  5957.     ReleaseDC (ghTTYWnd, hDC);
  5958.  
  5959.     /* Convert from screen pixels to points. */
  5960.     fontSize = MulDiv (-gpTTYInfo->lfTTYFont.lfHeight, 72, ppi);
  5961.     ++fontSize;        /* Fudge a little. */
  5962.  
  5963.  
  5964.     /* Get printer resolution and convert form points to printer pixels. */
  5965.     ppi = GetDeviceCaps (P_PrintDC, LOGPIXELSY);
  5966.     newFont.lfHeight =  -MulDiv (fontSize, ppi, 72);
  5967.     strcpy (newFont.lfFaceName, gpTTYInfo->lfTTYFont.lfFaceName);
  5968.     newFont.lfItalic = gpTTYInfo->lfTTYFont.lfItalic;
  5969.     newFont.lfWeight = gpTTYInfo->lfTTYFont.lfWeight;
  5970.     
  5971.  
  5972. #ifdef FDEBUG
  5973.     if (mswin_debug >= 8) {
  5974.         fprintf (mswin_debugfile, "                    font Size %d points\n",
  5975.             fontSize);
  5976.         fprintf (mswin_debugfile, "                    printer res %d ppi, font height %d pixels\n",
  5977.         ppi, -newFont.lfHeight);
  5978.         fprintf (mswin_debugfile, "                    paper height %d pixel, %d mm\n",
  5979.             GetDeviceCaps (P_PrintDC, VERTRES), 
  5980.             GetDeviceCaps (P_PrintDC, VERTSIZE));
  5981.     }
  5982. #endif
  5983.     }
  5984.     else {
  5985.     ppi = GetDeviceCaps (P_PrintDC, LOGPIXELSY);
  5986.     newFont.lfHeight =  -MulDiv (gPrintFontSize, ppi, 72);
  5987.     strcpy (newFont.lfFaceName, gPrintFontName);
  5988.     newFont.lfWeight = 0;
  5989.     if (strstr (gPrintFontStyle, "bold"))
  5990.         newFont.lfWeight = FW_BOLD;
  5991.     newFont.lfItalic = 0;
  5992.     if (strstr (gPrintFontStyle, "italic"))
  5993.         newFont.lfItalic = 1;
  5994.     }
  5995.  
  5996.     
  5997.     
  5998.     /* Fill out rest of font description and request font. */
  5999.     newFont.lfWidth =          0;
  6000.     newFont.lfEscapement =     0;
  6001.     newFont.lfOrientation =    0;
  6002.     newFont.lfUnderline =      0;
  6003.     newFont.lfStrikeOut =      0;
  6004.     newFont.lfCharSet =        ANSI_CHARSET;
  6005.     newFont.lfOutPrecision =   OUT_DEFAULT_PRECIS;
  6006.     newFont.lfClipPrecision =  CLIP_DEFAULT_PRECIS;
  6007.     newFont.lfQuality =        DEFAULT_QUALITY;
  6008.     newFont.lfPitchAndFamily = FIXED_PITCH;
  6009.     P_hFont = CreateFontIndirect (&newFont);
  6010.     if (P_hFont == NULL) {
  6011.     status = PE_FONT_FAILED;
  6012.     DeleteDC (P_PrintDC);
  6013.     goto Done;
  6014.     }
  6015.     
  6016.     
  6017.     /*
  6018.      * Start page.  
  6019.      * Must select font for each page or it returns to default.
  6020.      * Windows seems good about maping selected font to a font that 
  6021.      * will actually print on the printer.
  6022.      */
  6023.     StartPage (P_PrintDC);
  6024.     oldFont = SelectObject (P_PrintDC, P_hFont);
  6025.     
  6026.     
  6027.     /*
  6028.      * Find out about the font we got and set up page size and margins.
  6029.      * This assumes all pages are the same size - which seems reasonable.
  6030.      */
  6031.     GetTextMetrics (P_PrintDC, &tm);
  6032.     xChar = tm.tmAveCharWidth;            
  6033.     P_RowHeight = tm.tmHeight + tm.tmExternalLeading;
  6034.     
  6035.     /* HORZRES and VERTRES report size of page in printer pixels. */
  6036.     P_PageColumns = GetDeviceCaps (P_PrintDC, HORZRES) / xChar;
  6037.     P_PageRows = GetDeviceCaps (P_PrintDC, VERTRES) / P_RowHeight;
  6038.     
  6039.     /* We allow a margin at top and bottom measured in text rows. */
  6040.     P_PageRows -= VERTICLE_MARGIN * 2;
  6041.     P_TopOffset = VERTICLE_MARGIN * P_RowHeight;
  6042.     
  6043.     /* And allow for a left and right margine measured in characters. */
  6044.     P_PageColumns -= HORIZONTAL_MARGIN * 2;
  6045.     P_LeftOffset = HORIZONTAL_MARGIN * xChar;
  6046.     
  6047.     P_CurRow = 0;            /* Start counting at row 0. */
  6048.     P_CurCol = 0;            /* At character 0. */
  6049.     P_LineText = MemAlloc (P_PageColumns + 1);
  6050.     if (P_LineText == NULL) {
  6051.     EndDoc (P_PrintDC);
  6052.     DeleteObject (P_hFont);
  6053.     P_hFont = NULL;
  6054.     DeleteDC (P_PrintDC);
  6055.     P_PrintDC = NULL;
  6056.     status = PE_OUT_OF_MEMORY;
  6057.     goto Done;
  6058.     }
  6059.     
  6060.     
  6061. Done:
  6062.     return (status);
  6063. }
  6064.  
  6065.  
  6066.  
  6067. /* 
  6068.  * Called when printing is done.
  6069.  * xxx what happens if there is an error?  Will this get called?
  6070.  */
  6071. int
  6072. mswin_print_done (void)
  6073. {
  6074.     if (P_PrintDC != NULL) {
  6075.     if (P_LineText != NULL)
  6076.         MemFree (P_LineText);
  6077.     EndPage (P_PrintDC);
  6078.     EndDoc (P_PrintDC);
  6079.     DeleteObject (P_hFont);
  6080.     P_hFont = NULL;
  6081.     DeleteDC (P_PrintDC);
  6082.     P_PrintDC = NULL;
  6083.     }
  6084.     return (0);
  6085. }
  6086.  
  6087.  
  6088.  
  6089. /*
  6090.  * Return ponter to a text string that describes the erorr.
  6091.  */
  6092. char *
  6093. mswin_print_error (int error_code)
  6094. {
  6095.     int        i;
  6096.     
  6097.     for (i = 0; P_ErrorMessages[i].error_message != NULL; ++i) {
  6098.     if (P_ErrorMessages[i].error_code == error_code) 
  6099.         return (P_ErrorMessages[i].error_message);
  6100.     }
  6101.     return ("(Unknow error)");
  6102. }
  6103.  
  6104.  
  6105.  
  6106.  
  6107. /*
  6108.  * Add a single character to the current line.  
  6109.  * Only handles CRLF carrage control.
  6110.  */
  6111. int
  6112. mswin_print_char (int c)
  6113. {
  6114.     int        status;
  6115.     
  6116.     status = 0;
  6117.     switch (c) {
  6118.     case ASCII_CR:
  6119.     break;
  6120.  
  6121.     case ASCII_LF:
  6122.     status = _print_send_line ();
  6123.     break;
  6124.     
  6125.     case ASCII_TAB:
  6126.     if (P_CurCol == P_PageColumns)
  6127.         status = _print_send_line ();
  6128.     do {
  6129.         *(P_LineText + P_CurCol++) = ' ';
  6130.     } while (P_CurCol % PRINT_TAB_SIZE != 0 && P_CurCol < P_PageColumns);
  6131.     break;
  6132.  
  6133.     default:
  6134.     if (P_CurCol == P_PageColumns)
  6135.         status = _print_send_line ();
  6136.         *(P_LineText + P_CurCol++) = (char) c;
  6137.     break;
  6138.     }
  6139.     return (status);
  6140. }
  6141.     
  6142.  
  6143.  
  6144.  
  6145. /*
  6146.  * Send a string to the printer.
  6147.  */
  6148. int
  6149. mswin_print_text (char *text)
  6150. {
  6151.     if (text != NULL) {
  6152.     while (*text) 
  6153.         mswin_print_char (*(text++));
  6154.     }
  6155. }
  6156.  
  6157.  
  6158.  
  6159. #if 0
  6160. /*
  6161.  * Send a whole line to the printer.
  6162.  * Assume no carrage control in the line.
  6163.  */
  6164. int
  6165. mswin_print_line (char *line)
  6166. {
  6167.     
  6168.     int        status;
  6169.     int        linePos;
  6170.     int        lineLen;
  6171.     int        count;
  6172.     
  6173.     status = 0;
  6174.     lineLen = strlen (line);
  6175.     linePos = 0;
  6176.     
  6177.     /* Any text already in P_LineText is kept and appended to. */
  6178.     if (lineLen == 0) {
  6179.     /* If the line is empty, send that. */
  6180.     _print_send_line ();
  6181.     }
  6182.     else {
  6183.     /* Send the line to the printer.  Appending to anything that
  6184.      * was already there, and wrapping to subsequent lines if
  6185.      * there is more that will fit in one line. */
  6186.     while (lineLen > 0) {
  6187.         count = min (lineLen - linePos, P_PageColumns - P_CurCol);
  6188.         memcpy (P_LineText + P_CurCol, line + linePos, count);
  6189.         P_CurCol += count;
  6190.         linePos += count;
  6191.         lineLen -= count;
  6192.         _print_send_line ();
  6193.     }
  6194.     }
  6195.     return (0);
  6196. }
  6197. #endif
  6198.  
  6199.  
  6200.  
  6201.  
  6202.  
  6203.  
  6204.  
  6205.  
  6206. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  6207.  *
  6208.  *        File dialog boxes.
  6209.  *
  6210.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  6211.  
  6212. LOCAL char gHomeDir[PATH_MAX];
  6213. LOCAL char gLastDir[PATH_MAX];
  6214.  
  6215.  
  6216.  
  6217. /*
  6218.  * Keep track of the last dir visited.  Most of the time pine just passes us
  6219.  * the "home directory", which usually is not where the user wants to start.
  6220.  * Assume that the first time we are called we are being passed the home
  6221.  * direcory.
  6222.  */
  6223. static void
  6224. FillInitialDir (LPCSTR *iDir, char *targDir) 
  6225. {
  6226.     if (lstrlen (gHomeDir) == 0) {
  6227.     lstrcpy (gHomeDir, targDir);
  6228.     *iDir = targDir;
  6229.     }
  6230.     else if (lstrcmp (gHomeDir, targDir) == 0) 
  6231.         *iDir = gLastDir;
  6232.     else
  6233.         *iDir = targDir;
  6234. }
  6235.  
  6236.  
  6237.  
  6238. /*
  6239.  * Display a save file dialog box.
  6240.  *
  6241.  *    dir    >    directory to start search in
  6242.  *        <    directory finished in.
  6243.  *    fName    <    Name of file selectec
  6244.  *    nMaxFName    length of dir and fName.
  6245.  */
  6246. int
  6247. mswin_savefile (char *dir, char *fName, int nMaxFName)
  6248. {
  6249.     OPENFILENAME    ofn;
  6250.     char        filters[128];
  6251.     DWORD        rc;
  6252.     char        *p;
  6253.     size_t        l;
  6254.  
  6255.  
  6256.     /* Set filters array.  (pairs of null terminated strings, terminated
  6257.      * by a double null). */
  6258.     strcpy (filters, "Text Files (*.txt)#*.txt#All Files (*.*)#*.*#");
  6259.     for (p = filters; *p != '\0'; ++p) {
  6260.     if (*p == '#')
  6261.         *p = '\0';
  6262.     }
  6263.  
  6264.  
  6265.  
  6266.     /* Set up the BIG STRUCTURE. */
  6267.     memset (&ofn, 0, sizeof(ofn));
  6268.     ofn.lStructSize = sizeof (OPENFILENAME);
  6269.     ofn.hwndOwner = ghTTYWnd;
  6270.     ofn.lpstrFilter = filters;
  6271.     ofn.lpstrCustomFilter = NULL;
  6272.     ofn.nFilterIndex = 1;
  6273.     ofn.lpstrFile = fName;
  6274.     ofn.nMaxFile = nMaxFName;
  6275.     ofn.lpstrFileTitle = NULL;
  6276.     ofn.nMaxFileTitle = 0;
  6277.     FillInitialDir (&ofn.lpstrInitialDir, dir);
  6278.     ofn.lpstrTitle = "Save To File";
  6279.     ofn.Flags = OFN_NOREADONLYRETURN | 
  6280.             OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
  6281.     ofn.lpstrDefExt = "txt";
  6282.  
  6283.     if (GetSaveFileName (&ofn)) {
  6284.         
  6285.     /* Copy directory name to dir. */
  6286.     strcpy (dir, fName);
  6287.     if (dir[ofn.nFileOffset-1] == '\\')
  6288.         dir[ofn.nFileOffset-1] = '\0';
  6289.         else
  6290.         dir[ofn.nFileOffset] = '\0';
  6291.     
  6292.     /* Remember last dir visited. */
  6293.     lstrcpy (gLastDir, dir);
  6294.     
  6295.     /* Move file name portion to beginning of fName buffer. */
  6296.     p = fName + ofn.nFileOffset;
  6297.     l = strlen (p) + 1;
  6298.     memmove (fName, p, l);
  6299.     return (0);
  6300.     }
  6301.     else {
  6302.     rc = CommDlgExtendedError ();
  6303.     return (-1);
  6304.     }
  6305. }
  6306.  
  6307.  
  6308.  
  6309.  
  6310. /*
  6311.  * Display an open file dialog box.
  6312.  *
  6313.  *    dir    >    directory to start search in
  6314.  *        <    directory finished in.
  6315.  *    fName    <    Name of file selectec
  6316.  *    nMaxFName    length of dir and fName.
  6317.  */
  6318. int
  6319. mswin_openfile (char *dir, char *fName, int nMaxFName)
  6320. {
  6321.     OPENFILENAME    ofn;
  6322.     char        filters[128];
  6323.     DWORD        rc;
  6324.     char        *p;
  6325.     size_t        l;
  6326.  
  6327.  
  6328.     /* Set filters array.  (pairs of null terminated strings, terminated
  6329.      * by a double null). */
  6330.     strcpy (filters, "Text Files (*.txt)#*.txt#All Files (*.*)#*.*#");
  6331.     for (p = filters; *p != '\0'; ++p) {
  6332.     if (*p == '#')
  6333.         *p = '\0';
  6334.     }
  6335.     
  6336.     
  6337.  
  6338.     /* Set up the BIG STRUCTURE. */
  6339.     memset (&ofn, 0, sizeof(ofn));
  6340.     ofn.lStructSize = sizeof (OPENFILENAME);
  6341.     ofn.hwndOwner = ghTTYWnd;
  6342.     ofn.lpstrFilter = filters;
  6343.     ofn.lpstrCustomFilter = NULL;
  6344.     ofn.nFilterIndex = 1;
  6345.     ofn.lpstrFile = fName;
  6346.     ofn.nMaxFile = nMaxFName;
  6347.     ofn.lpstrFileTitle = NULL;
  6348.     ofn.nMaxFileTitle = 0;
  6349.     FillInitialDir (&ofn.lpstrInitialDir, dir);
  6350.     ofn.lpstrTitle = "Select File";
  6351.     ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
  6352.     ofn.lpstrDefExt = "txt";
  6353.  
  6354.     if (GetOpenFileName (&ofn)) {
  6355.         
  6356.     /* Copy directory name to dir. */
  6357.     strcpy (dir, fName);
  6358.     if (dir[ofn.nFileOffset-1] == '\\')
  6359.         dir[ofn.nFileOffset-1] = '\0';
  6360.         else
  6361.         dir[ofn.nFileOffset] = '\0';
  6362.     
  6363.     /* Remember last dir visited. */
  6364.     lstrcpy (gLastDir, dir);
  6365.     
  6366.     /* Move file name portion to beginning of fName buffer. */
  6367.     p = fName + ofn.nFileOffset;
  6368.     l = strlen (p) + 1;
  6369.     memmove (fName, p, l);
  6370.     return (0);
  6371.     }
  6372.     else {
  6373.     rc = CommDlgExtendedError ();
  6374.     return (-1);
  6375.     }
  6376. }
  6377.     
  6378.     
  6379.  
  6380.  
  6381.  
  6382.  
  6383. /*---------------------------------------------------------------------------
  6384.  */
  6385.  
  6386. /*
  6387.  * pico_XXcolor() - each function sets a particular attribute
  6388.  */
  6389. pico_nfcolor(s)
  6390. char *s;
  6391. {
  6392.     SetColorAttribute (&gpTTYInfo->rgbFGColor, s);
  6393. }
  6394.  
  6395. pico_nbcolor(s)
  6396. char *s;
  6397. {
  6398.     SetColorAttribute (&gpTTYInfo->rgbBGColor, s);
  6399. }
  6400.  
  6401. pico_rfcolor(s)
  6402. char *s;
  6403. {
  6404.     SetColorAttribute (&gpTTYInfo->rgbRFGColor, s);
  6405. }
  6406.  
  6407. pico_rbcolor(s)
  6408. char *s;
  6409. {
  6410.     SetColorAttribute (&gpTTYInfo->rgbRBGColor, s);
  6411. }
  6412.  
  6413.  
  6414.  
  6415.  
  6416.  
  6417. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  6418.  *
  6419.  *        Signal and alarm functions
  6420.  *
  6421.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  6422.  
  6423. /*
  6424.  * Provide a rough implementation of the SIGALRM and alarm functions
  6425.  */
  6426.  
  6427.  
  6428.  
  6429. /*
  6430.  * Set a new handler for a signal.
  6431.  */
  6432. void (__cdecl * __cdecl signal (int sig,void (__cdecl *hndlr)(int)))(int)
  6433.  
  6434. {
  6435.     SignalType    oldValue;
  6436.     
  6437.     if (sig == SIGALRM) {
  6438.     oldValue = gSignalAlarm;
  6439.     gSignalAlarm = hndlr;
  6440.     return (oldValue);
  6441.     }
  6442.     if (sig == SIGHUP) {
  6443.     oldValue = gSignalHUP;
  6444.     gSignalHUP = hndlr;
  6445.     return (oldValue);
  6446.     }
  6447.     
  6448.     /* All other's are always ignored. */
  6449.     return (SIG_IGN);
  6450. }
  6451.  
  6452.  
  6453.  
  6454.  
  6455. /*
  6456.  * Set the alarm expiration time (in seconds)
  6457.  */
  6458. int
  6459. alarm (int seconds)
  6460. {
  6461.     int        prevtime;
  6462.     
  6463.     prevtime = gAlarmTimeout ? (gAlarmTimeout - (GetTickCount () / 1000)): 0;
  6464.     gAlarmTimeout = seconds ? (GetTickCount() / 1000) + seconds : 0;
  6465.     MyTimerSet ();
  6466.     return (prevtime);
  6467. }
  6468.  
  6469.  
  6470.  
  6471. /*
  6472.  * Deliver and clear the alarm.
  6473.  */
  6474. void
  6475. AlarmDeliver ()
  6476. {
  6477.     if (gSignalAlarm != SIG_DFL && gSignalAlarm != SIG_IGN) {
  6478.     /* Clear AlarmTimeout BEFORE calling handler.  handler may call back
  6479.      * to reset timeout. */
  6480.     gAlarmTimeout = 0;
  6481.     MyTimerSet ();
  6482.     gSignalAlarm (SIGALRM);
  6483.     }
  6484. }
  6485.  
  6486.  
  6487.  
  6488. void
  6489. HUPDeliver ()
  6490. {
  6491.     if (gSignalHUP) {
  6492.     gSignalHUP (SIGHUP);
  6493.     exit (0);
  6494.     }
  6495. }
  6496.  
  6497.  
  6498.  
  6499.  
  6500. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  6501.  *
  6502.  *        Printer font selection menu
  6503.  *
  6504.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  6505.  
  6506. /*
  6507.  * Set the print font to be the same as the window font.
  6508.  * Toggle setting.
  6509.  */
  6510. void
  6511. PrintFontSameAs (HWND hWnd)
  6512. {
  6513.     HDC            hDC;
  6514.     int            ppi;
  6515.     PTTYINFO        pTTYInfo;
  6516.     
  6517.     
  6518.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  6519.     if (pTTYInfo == NULL)
  6520.     return;
  6521.     
  6522.     if (gPrintFontSameAs) {
  6523.         
  6524.     /* No longer same as window font.  Use window font as starting point
  6525.      * for new printer font.  User may later modify printer font. */
  6526.     hDC = GetDC (hWnd);
  6527.     ppi = GetDeviceCaps (hDC, LOGPIXELSY);
  6528.     ReleaseDC (ghTTYWnd, hDC);
  6529.     ExtractFontInfo (&pTTYInfo->lfTTYFont, gPrintFontName, 
  6530.             &gPrintFontSize, gPrintFontStyle, ppi);
  6531.     gPrintFontSameAs = FALSE;
  6532.     }
  6533.     else {
  6534.         
  6535.     /* Set to be same as the printer font.  Destroy printer font info
  6536.      * and set "sameAs" flag to TRUE. */
  6537.     gPrintFontName[0] = '\0';
  6538.     gPrintFontSameAs = TRUE;
  6539.     }
  6540.     DidResize (gpTTYInfo);
  6541. }
  6542.  
  6543.  
  6544.  
  6545.  
  6546.  
  6547. void
  6548. PrintFontSelect (HWND hWnd)
  6549. {
  6550.     CHOOSEFONT        cfTTYFont;
  6551.     LOGFONT        newFont;
  6552.     DWORD        drc;
  6553.     int            ppi;
  6554.     HDC            hDC;
  6555.  
  6556.     
  6557.  
  6558.     hDC = GetDC (hWnd);
  6559.     ppi = GetDeviceCaps (hDC, LOGPIXELSY);
  6560.     ReleaseDC (ghTTYWnd, hDC);
  6561.  
  6562.     
  6563.     newFont.lfHeight =  -MulDiv (gPrintFontSize, ppi, 72);
  6564.     strcpy (newFont.lfFaceName, gPrintFontName);
  6565.     newFont.lfWeight = 0;
  6566.     if (strstr (gPrintFontStyle, "bold"))
  6567.     newFont.lfWeight = FW_BOLD;
  6568.     newFont.lfItalic = 0;
  6569.     if (strstr (gPrintFontStyle, "italic"))
  6570.     newFont.lfItalic = 1;
  6571.  
  6572.     newFont.lfWidth =          0;
  6573.     newFont.lfEscapement =     0;
  6574.     newFont.lfOrientation =    0;
  6575.     newFont.lfUnderline =      0;
  6576.     newFont.lfStrikeOut =      0;
  6577.     newFont.lfCharSet =        ANSI_CHARSET;
  6578.     newFont.lfOutPrecision =   OUT_DEFAULT_PRECIS;
  6579.     newFont.lfClipPrecision =  CLIP_DEFAULT_PRECIS;
  6580.     newFont.lfQuality =        DEFAULT_QUALITY;
  6581.     newFont.lfPitchAndFamily = FIXED_PITCH;
  6582.     
  6583.  
  6584.     cfTTYFont.lStructSize    = sizeof (CHOOSEFONT);
  6585.     cfTTYFont.hwndOwner      = hWnd ;
  6586.     cfTTYFont.hDC            = NULL ;
  6587.     cfTTYFont.rgbColors      = 0;
  6588.     cfTTYFont.lpLogFont      = &newFont;
  6589.     cfTTYFont.Flags          = CF_BOTH | CF_FIXEDPITCHONLY |
  6590.         CF_INITTOLOGFONTSTRUCT | CF_ANSIONLY | 
  6591.         CF_FORCEFONTEXIST | CF_LIMITSIZE;
  6592.     cfTTYFont.nSizeMin         = FONT_MIN_SIZE;
  6593.     cfTTYFont.nSizeMax         = FONT_MAX_SIZE;
  6594.     cfTTYFont.lCustData      = 0 ;
  6595.     cfTTYFont.lpfnHook       = NULL ;
  6596.     cfTTYFont.lpTemplateName = NULL ;
  6597.     cfTTYFont.hInstance      = GET_HINST (hWnd);
  6598.  
  6599.  
  6600.     if (ChooseFont (&cfTTYFont)) {
  6601.     ExtractFontInfo (&newFont, gPrintFontName, &gPrintFontSize, 
  6602.                     gPrintFontStyle, ppi);
  6603.     DidResize (gpTTYInfo);
  6604.     }
  6605.     else
  6606.     /* So I can see with the debugger. */
  6607.     drc = CommDlgExtendedError();
  6608. }
  6609.  
  6610.  
  6611. void
  6612. ExtractFontInfo (LOGFONT *pFont, char *fontName, int *fontSize, 
  6613.                     char *fontStyle, int ppi)
  6614. {
  6615.     char        *sep[] = {"", ", "};
  6616.     int            iSep = 0;
  6617.  
  6618.     
  6619.     strcpy (fontName, pFont->lfFaceName);
  6620.  
  6621.     *fontStyle = '\0';
  6622.     if (pFont->lfWeight >= FW_BOLD) {
  6623.     strcat (fontStyle, "bold");
  6624.     iSep = 1;
  6625.     }
  6626.     if (pFont->lfItalic) {
  6627.     strcat (fontStyle, sep[iSep]);
  6628.     strcat (fontStyle, "italic");
  6629.     }
  6630.  
  6631.     *fontSize = MulDiv (-pFont->lfHeight, 72, ppi);
  6632. }
  6633.  
  6634.  
  6635.  
  6636.  
  6637.  
  6638.     
  6639.     
  6640. LOCAL void
  6641. DidResize (PTTYINFO pTTYInfo)
  6642. {
  6643.     int            i;
  6644.     
  6645.     for (i = 0; i < RESIZE_CALLBACK_ARRAY_SIZE; ++i) {
  6646.     if (pTTYInfo->resizer[i] != NULL) 
  6647.         pTTYInfo->resizer[i] (pTTYInfo->actNRow, pTTYInfo->actNColumn);
  6648.     }
  6649. }
  6650.  
  6651.  
  6652.     
  6653.     
  6654. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  6655.  *
  6656.  *        Cut, Copy, and Paste operations
  6657.  *
  6658.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  6659.  
  6660.  
  6661. /*
  6662.  * Gets called right before the menu is displayed so we can make
  6663.  * any last minute adjustments.
  6664.  */
  6665. LOCAL void
  6666. UpdateMenu (HWND hWnd)
  6667. {
  6668.     HMENU        hMenu;
  6669.     HMENU        hCmdMenu;
  6670.     BOOL        brc;
  6671.     PTTYINFO        pTTYInfo;
  6672.     int            i;
  6673.     
  6674.     pTTYInfo = (PTTYINFO) GetWindowLong (hWnd, GWL_PTTYINFO);
  6675.     if (pTTYInfo == NULL)
  6676.     return;
  6677.  
  6678.     hMenu = GetMenu (hWnd);
  6679.     if (hMenu == NULL)
  6680.     return;
  6681.     
  6682.     if (ghPaste == NULL) {
  6683.     /* 
  6684.      * Not pasting.  If text is available on clipboard and we are
  6685.      * at a place where we can paste, enable past menu option.
  6686.      * Also check if we currently have a selection that can be copied
  6687.      * or cut.  If so, we don't want to paste into a selection - it
  6688.      * works but it is slow and probably not what the user intended.
  6689.      */
  6690.     if (IsClipboardFormatAvailable (CF_TEXT) && gPasteEnabled && 
  6691.         gCopyCutFunction == NULL)
  6692.         EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND | MF_ENABLED);
  6693.     else
  6694.         EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND | MF_GRAYED);
  6695.     EnableMenuItem (hMenu, IDM_EDIT_CANCEL_PASTE, MF_BYCOMMAND | MF_GRAYED);
  6696.     }
  6697.     else {
  6698.     /* Currently pasting so disable paste and enable cancel paste. */
  6699.     EnableMenuItem (hMenu, IDM_EDIT_PASTE, MF_BYCOMMAND | MF_GRAYED);
  6700.     EnableMenuItem (hMenu, IDM_EDIT_CANCEL_PASTE, MF_BYCOMMAND | MF_ENABLED);
  6701.     }
  6702.     
  6703.     if (SelAvailable ()) {
  6704.     EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND | MF_GRAYED);
  6705.     EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND | MF_ENABLED);
  6706.     EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND, 
  6707.                 MF_BYCOMMAND | MF_ENABLED);
  6708.     } else {
  6709.     if (gAllowCut)
  6710.         EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND | MF_ENABLED);
  6711.         else
  6712.         EnableMenuItem (hMenu, IDM_EDIT_CUT, MF_BYCOMMAND | MF_GRAYED);
  6713.  
  6714.         if (gAllowCopy) {
  6715.         EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND | MF_ENABLED);
  6716.         EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND, 
  6717.                 MF_BYCOMMAND | MF_ENABLED);    
  6718.     }
  6719.         else {
  6720.         EnableMenuItem (hMenu, IDM_EDIT_COPY, MF_BYCOMMAND | MF_GRAYED);
  6721.         EnableMenuItem (hMenu, IDM_EDIT_COPY_APPEND, 
  6722.                 MF_BYCOMMAND | MF_GRAYED);    
  6723.     }
  6724.     }
  6725.  
  6726.  
  6727.  
  6728.     /*
  6729.      * Set up Font selection menu
  6730.      */
  6731.     if (gPrintFontName[0] == '\0') {
  6732.     CheckMenuItem (hMenu, IDM_OPT_FONTSAMEAS, MF_BYCOMMAND | MF_CHECKED);
  6733.     EnableMenuItem (hMenu, IDM_OPT_SETPRINTFONT, 
  6734.                         MF_BYCOMMAND | MF_GRAYED);
  6735.     }
  6736.     else {
  6737.     CheckMenuItem (hMenu, IDM_OPT_FONTSAMEAS, 
  6738.                         MF_BYCOMMAND | MF_UNCHECKED);
  6739.     EnableMenuItem (hMenu, IDM_OPT_SETPRINTFONT, 
  6740.                         MF_BYCOMMAND | MF_ENABLED);
  6741.     }
  6742.  
  6743.     
  6744.     /*
  6745.      * Check toolbar menu.
  6746.      */
  6747.     EnableMenuItem (hMenu, IDM_OPT_TOOLBAR, MF_BYCOMMAND | MF_ENABLED);
  6748.     CheckMenuItem (hMenu, IDM_OPT_TOOLBAR, MF_BYCOMMAND | 
  6749.         (pTTYInfo->toolBarSize > 0 ? MF_CHECKED : MF_UNCHECKED));
  6750.     EnableMenuItem (hMenu, IDM_OPT_TOOLBARPOS, MF_BYCOMMAND | MF_ENABLED);
  6751.     CheckMenuItem (hMenu, IDM_OPT_TOOLBARPOS, MF_BYCOMMAND | 
  6752.         (pTTYInfo->toolBarTop > 0 ? MF_CHECKED : MF_UNCHECKED));
  6753.  
  6754.  
  6755.  
  6756.     /*
  6757.      * Check the dialogs menu.
  6758.      */
  6759.     /* xxx EnableMenuItem (hMenu, IDM_OPT_USEDIALOGS, MF_BYCOMMAND | MF_ENABLED);*/
  6760.     CheckMenuItem (hMenu, IDM_OPT_USEDIALOGS, MF_BYCOMMAND | 
  6761.         (gfUseDialogs ? MF_CHECKED : MF_UNCHECKED));
  6762.     CheckMenuItem (hMenu, IDM_OPT_USEACCEL, MF_BYCOMMAND | 
  6763.         (pTTYInfo->hAccel ? MF_CHECKED : MF_UNCHECKED));
  6764.  
  6765.  
  6766.     /*
  6767.      * Set up command menu.
  6768.      */
  6769.     if (!pTTYInfo->menuItemsCurrent) {
  6770.     for (i = 0; i < KS_COUNT; ++i) {
  6771. #if 0
  6772.         EnableMenuItem (hMenu, i + KS_RANGESTART, MF_BYCOMMAND | 
  6773.          (pTTYInfo->menuItems[i].miActive ? MF_ENABLED : MF_GRAYED));
  6774. #else
  6775.         if (pTTYInfo->menuItems[i].miActive)
  6776.         EnableMenuItem (hMenu, i + KS_RANGESTART, MF_BYCOMMAND | MF_ENABLED);
  6777.         else
  6778.         EnableMenuItem (hMenu, i + KS_RANGESTART, MF_BYCOMMAND | MF_GRAYED);
  6779. #endif
  6780.     }
  6781.     pTTYInfo->menuItemsCurrent = TRUE;
  6782.     }
  6783. }
  6784.  
  6785.  
  6786.  
  6787. /*
  6788.  * Cut region to kill buffer.
  6789.  */
  6790. LOCAL void
  6791. EditCut (void)
  6792. {
  6793.     HANDLE        hCB;
  6794.     
  6795.     if(gCopyCutFunction == kremove){
  6796.     hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
  6797.     if (hCB != NULL) {
  6798.         kdelete();        /* Clear current kill buffer. */
  6799.         copyregion (1, 0);
  6800.         EditDoCopyData (hCB, 0);
  6801.         killregion (1, 0);    /* Kill Region. */
  6802.         update ();        /* And update the screen */
  6803.         }
  6804.     }
  6805. }
  6806.  
  6807.  
  6808. /*
  6809.  * Copy region to kill buffer. 
  6810.  */
  6811. LOCAL void
  6812. EditCopy (void)
  6813. {
  6814.     HANDLE        hCB;
  6815.     
  6816.     if (SelAvailable()) {
  6817.     /* This is a copy of the windows selection. */
  6818.     hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
  6819.     if (hCB != NULL) 
  6820.         SelDoCopy (hCB, 0);
  6821.     } 
  6822.     else {
  6823.         
  6824.     /* Otherwise, it's a Pico/Pine copy. */
  6825.     if(gCopyCutFunction == kremove){
  6826.         kdelete();        /* Clear current kill buffer. */
  6827.         copyregion (1, 0);
  6828.     }
  6829.  
  6830.     hCB = GlobalAlloc (GMEM_MOVEABLE, 0);
  6831.     if (hCB != NULL) 
  6832.         EditDoCopyData (hCB, 0);
  6833.     }
  6834. }
  6835.  
  6836.  
  6837.  
  6838. /*
  6839.  * Called in responce to "Copy Append" menu command, when there is an active
  6840.  * Windows selection on the screen.
  6841.  */
  6842. LOCAL void
  6843. EditCopyAppend (void)
  6844. {
  6845.     HANDLE    hCB;
  6846.     HANDLE    hMyCopy;
  6847.     char    *pCB;
  6848.     char    *pMyCopy;
  6849.     size_t    cbSize;
  6850.  
  6851.     /* Attempt to copy clipboard data to my own handle. */
  6852.     hMyCopy = NULL;
  6853.     if (OpenClipboard (ghTTYWnd)) {        /* And can get clipboard. */
  6854.     hCB = GetClipboardData (CF_TEXT);
  6855.     if (hCB != NULL) {            /* And can get data. */
  6856.         pCB = GlobalLock (hCB);
  6857.         cbSize = strlen (pCB);        /* It's a null term string. */
  6858.         hMyCopy = GlobalAlloc (GMEM_MOVEABLE, cbSize);
  6859.         if (hMyCopy != NULL) {        /* And can get memory. */
  6860.         pMyCopy = GlobalLock (hMyCopy);
  6861.         if (pMyCopy != NULL) {
  6862.             memcpy (pMyCopy, pCB, cbSize);  /* Copy data. */
  6863.             GlobalUnlock (hMyCopy);
  6864.         }
  6865.         else {
  6866.             GlobalFree (hMyCopy);
  6867.             hMyCopy = NULL;
  6868.         }
  6869.         }
  6870.         GlobalUnlock (hCB);
  6871.     }                    /* GetClipboardData. */
  6872.     CloseClipboard ();
  6873.     }                    /* OpenClipboard. */
  6874.     
  6875.  
  6876.  
  6877.     /* Now, if I got a copy, append current selection to that
  6878.      * and stuff it back into the clipboard. */
  6879.     if (hMyCopy != NULL) {
  6880.     if (SelAvailable ()) {
  6881.         SelDoCopy (hMyCopy, cbSize);
  6882.     }
  6883.     else {
  6884.         if(gCopyCutFunction == kremove) {
  6885.         kdelete();        /* Clear current kill buffer. */
  6886.         copyregion (1, 0);
  6887.         }
  6888.         EditDoCopyData (hMyCopy, cbSize);
  6889.     }
  6890.     }
  6891. }
  6892.  
  6893.  
  6894.  
  6895.  
  6896.  
  6897.  
  6898.  
  6899.  
  6900.  
  6901. /*
  6902.  * Copy data from the kill buffer to the clipboard.  Handle LF->CRLF
  6903.  * translation if necessary.
  6904.  */
  6905. LOCAL void
  6906. EditDoCopyData (HANDLE hCB, DWORD lenCB)
  6907. {
  6908.     char        *pCB;
  6909.     char        *p;
  6910.     char        c;
  6911.     char        lastc = '\0';
  6912.     DWORD        cbSize;            /* Allocated size of hCB. */
  6913.     DWORD        i;
  6914. #define    BUF_INC    4096
  6915.  
  6916.     if (gCopyCutFunction != NULL) {        /* If there really is data. */
  6917.     if (OpenClipboard (ghTTYWnd)) {        /* ...and we get the CB. */
  6918.         if (EmptyClipboard ()) {        /* ...and clear previous CB.*/
  6919.         pCB = GlobalLock (hCB);
  6920.         p = pCB + lenCB;
  6921.         cbSize = lenCB;
  6922.         /* Copy it. (BUG: change int arg) */
  6923.         for(i = 0L; (c = (*gCopyCutFunction)((int)i)) != -1; i++){
  6924.             /*
  6925.              * Rather than fix every function that might
  6926.              * get called for character retrieval to supply
  6927.              * CRLF EOLs, let's just fix it here.  The downside
  6928.              * is a much slower copy for large buffers, but
  6929.              * hey, what do they want?
  6930.              */
  6931.             if(lenCB + 2L >= cbSize){
  6932.             cbSize += BUF_INC;
  6933.             GlobalUnlock (hCB);
  6934.             hCB = GlobalReAlloc (hCB, cbSize, GMEM_MOVEABLE);
  6935.             if (hCB == NULL)
  6936.               return;
  6937.  
  6938.             pCB = GlobalLock (hCB);
  6939.             p = pCB + lenCB;
  6940.             }
  6941.  
  6942.             if(c == ASCII_LF && lastc != ASCII_CR) {
  6943.               *p++ = ASCII_CR;    /* insert CR before LF */
  6944.               lenCB++;
  6945.             }
  6946.  
  6947.             *p++ = lastc = c;
  6948.             lenCB++;
  6949.         }
  6950.  
  6951.         *p = '\0';
  6952.         GlobalUnlock (hCB);
  6953.  
  6954.         if (SetClipboardData (CF_TEXT, hCB) == NULL)
  6955.           /* Failed!  Free the data. */
  6956.           GlobalFree (hCB);
  6957.         }
  6958.         CloseClipboard (); 
  6959.         }
  6960.     }
  6961. }
  6962.  
  6963.  
  6964.  
  6965. /*
  6966.  * Get a handle to the current (text) clipboard and make my own copy.
  6967.  * Keep my copy locked because I'll be using it to read bytes from.
  6968.  */
  6969. LOCAL void
  6970. EditPaste (void)
  6971. {
  6972.     HANDLE    hCB;
  6973.     char    *pCB;
  6974.     char    *pPaste;
  6975.     size_t    cbSize;
  6976.    
  6977.     if (ghPaste == NULL) {        /* If we are not already pasting. */
  6978.     if (OpenClipboard (ghTTYWnd)) {        /* And can get clipboard. */
  6979.         hCB = GetClipboardData (CF_TEXT);
  6980.         if (hCB != NULL) {            /* And can get data. */
  6981.         pCB = GlobalLock (hCB);
  6982.         cbSize = strlen (pCB);        /* It's a null term string. */
  6983.         ghPaste = GlobalAlloc (GMEM_MOVEABLE, cbSize+1);
  6984.         if (ghPaste != NULL) {        /* And can get memory. */
  6985.             gpPasteNext = GlobalLock (ghPaste);
  6986.             memcpy (gpPasteNext, pCB, cbSize+1);  /* Copy data. */
  6987.             /* Keep ghPaste locked. */
  6988.  
  6989.             /*
  6990.              * If we're paste is enabled but limited to the first
  6991.              * line of the clipboard, prune the paste buffer...
  6992.              */
  6993.             if(gPasteEnabled == MSWIN_PASTE_LINE
  6994.                && (pPaste = strchr(gpPasteNext, ASCII_CR))){
  6995.             *pPaste = '\0';
  6996.             cbSize  = strlen(gpPasteNext);
  6997.             }
  6998.  
  6999.             gPasteBytesRemain = cbSize;
  7000.             gPasteWasCR = FALSE;
  7001. #ifdef FDEBUG
  7002.             if (mswin_debug > 8) 
  7003.             fprintf (mswin_debugfile, "EditPaste::  Paste %d bytes\n",
  7004.                     gPasteBytesRemain);
  7005. #endif
  7006.         }
  7007.         GlobalUnlock (hCB);
  7008.         }
  7009.         CloseClipboard ();
  7010.         }
  7011.     }
  7012. }
  7013.  
  7014.  
  7015.  
  7016.  
  7017.  
  7018.  
  7019. /*
  7020.  * Cancel an active paste operation.
  7021.  */
  7022. LOCAL void
  7023. EditCancelPaste (void)
  7024. {
  7025.     HANDLE    hCB;
  7026.     char    *pCB;
  7027.     char    *pPaste;
  7028.     size_t    cbSize;
  7029.    
  7030.     if (ghPaste != NULL) {    /* Must be pasting. */
  7031.     GlobalUnlock (ghPaste);    /* Then Unlock... */
  7032.     GlobalFree (ghPaste);    /* ...and free the paste buffer. */
  7033.     ghPaste = NULL;        /* Indicates no paste data. */
  7034.     gpPasteNext = NULL;        /* Just being tidy. */
  7035.     gPasteBytesRemain = 0;    /* ditto. */
  7036. #ifdef FDEBUG
  7037.     if (mswin_debug > 8) 
  7038.         fprintf (mswin_debugfile, "EditCancelPaste::  Free Paste Data\n");
  7039. #endif
  7040.     }
  7041. }
  7042.  
  7043.  
  7044. /*
  7045.  * Get the next byte from the paste buffer.  If all bytes have been
  7046.  * retreived, free the paste buffer.
  7047.  * Map all CRLF sequence to a single CR.
  7048.  */
  7049. LOCAL WORD
  7050. EditPasteGet (void)
  7051. {
  7052.     int        b;
  7053.     
  7054.     b = MSWIN_KEY_NODATA;
  7055.     if (ghPaste != NULL) {        /* ghPaste tells if we are pasting. */
  7056.         if (gPasteBytesRemain > 0) {    /* Just in case... */
  7057.         b = *gpPasteNext++;        /* Get one byte and move pointer. */
  7058.         --gPasteBytesRemain;    /*    one less. */
  7059.         if (gPasteWasCR && b == ASCII_LF) {
  7060.         if (gPasteBytesRemain) {
  7061.             b = *gpPasteNext++;    /* Skip of LF. */
  7062.             --gPasteBytesRemain;
  7063.             }
  7064.         else 
  7065.             b = MSWIN_KEY_NODATA;  /* Ignore last LF. */
  7066.         }
  7067.         gPasteWasCR = (b == ASCII_CR);
  7068. #ifdef FDEBUG
  7069.         if (mswin_debug > 8) 
  7070.         fprintf (mswin_debugfile, "EditPasteGet::  char %c, gPasteWasCR %d, gPasteBytesRemain %d\n",
  7071.             b, gPasteWasCR, gPasteBytesRemain);
  7072. #endif
  7073.         }
  7074.     if (gPasteBytesRemain <= 0) {    /* All Done? */
  7075.         GlobalUnlock (ghPaste);    /* Then Unlock... */
  7076.         GlobalFree (ghPaste);    /* ...and free the paste buffer. */
  7077.         ghPaste = NULL;        /* Indicates no paste data. */
  7078.         gpPasteNext = NULL;        /* Just being tidy. */
  7079.         gPasteBytesRemain = 0;    /* ditto. */
  7080. #ifdef FDEBUG
  7081.         if (mswin_debug > 8) 
  7082.         fprintf (mswin_debugfile, "EditPasteGet::  Free Paste Data\n");
  7083. #endif
  7084.         }
  7085.     }
  7086.     return (b);
  7087. }
  7088.  
  7089.  
  7090. /*
  7091.  * Return true if Paste data is available.  If gpPaste != NULL then there
  7092.  * is paste data.
  7093.  */
  7094. LOCAL BOOL
  7095. EditPasteAvailable (void)
  7096. {
  7097.     return (ghPaste != NULL);
  7098. }
  7099.  
  7100.  
  7101.  
  7102.  
  7103.  
  7104. LOCAL void
  7105. ShowHelp (void)
  7106. {
  7107.     size_t    len;
  7108.     
  7109.     if (gpHelpText != NULL || gpHelpLines != NULL) {
  7110.     mswin_displaytext (gpHelpTitle, gpHelpText, gpHelpLen,
  7111.                gpHelpLines, 0, MSWIN_DT_NODELETE);
  7112.     }
  7113. }
  7114.  
  7115.  
  7116.  
  7117.  
  7118.  
  7119. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  7120.  *
  7121.  *                 Adjust the timer fewquency as needed.
  7122.  *
  7123.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  7124.  
  7125. LOCAL void
  7126. MyTimerSet (void)
  7127. {
  7128.     UINT    period;
  7129.     /* Decide on period to use. */
  7130.     if (gAllowMouseTrack)
  7131.     period = MY_TIMER_EXCEEDINGLY_SHORT_PERIOD;
  7132.     else if (gAlarmTimeout != 0)
  7133.     period = MY_TIMER_VERY_SHORT_PERIOD;
  7134.     else if (gOnTaskList != NULL)
  7135.     period = MY_TIMER_SHORT_PERIOD;
  7136.     else
  7137.     period = MY_TIMER_PERIOD;
  7138.  
  7139.     if (period != gTimerCurrentPeriod) {
  7140.     if (SetTimer (ghTTYWnd, MY_TIMER_ID, period, NULL) == 0) 
  7141.         MessageBox (ghTTYWnd, TIMER_FAIL_MESSAGE, NULL, 
  7142.                  MB_OK | MB_ICONINFORMATION);
  7143.         else
  7144.         gTimerCurrentPeriod = period;
  7145.     }
  7146. }
  7147.  
  7148.  
  7149.  
  7150.  
  7151.  
  7152. void
  7153. mswin_setperiodiccallback (callback_t periodiccb, long period)
  7154. {
  7155.     if (periodiccb != NULL && period > 0) {
  7156.     gPeriodicCallback = periodiccb;
  7157.     gPeriodicCBTime = period;
  7158.     gPeriodicCBTimeout = GetTickCount () / 1000 + gPeriodicCBTime;
  7159.     }
  7160.     else {
  7161.     gPeriodicCallback = NULL;
  7162.     }
  7163. }
  7164.  
  7165.  
  7166.  
  7167.  
  7168.  
  7169. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  7170.  *
  7171.  *                  On Task processing
  7172.  *
  7173.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  7174.  
  7175.  
  7176. WINHAND
  7177. mswin_inst2task (WINHAND hModule)
  7178. {
  7179. #ifndef    WIN32
  7180.     TASKENTRY        te;
  7181.     MODULEENTRY        me;
  7182.     BOOL        brc;
  7183.     
  7184.  
  7185.     memset (&te, 0, sizeof (te));
  7186.     te.dwSize = sizeof (te);
  7187.     
  7188. #ifdef FDEBUG
  7189.     if (mswin_debug >= 8) 
  7190.     fprintf (mswin_debugfile, "mswin_inst2task:  look for x%x\n", hModule);
  7191. #endif
  7192.  
  7193.     brc = TaskFirst (&te);
  7194.     while (brc) {
  7195. #ifdef FDEBUG
  7196.     if (mswin_debug >= 8)
  7197.         fprintf (mswin_debugfile, "  task:  '%s', hTask x%x, module x%x, inst x%x\n", 
  7198.             te.szModule, (UINT) te.hTask, (UINT) te.hModule, 
  7199.             (UINT) te.hInst);
  7200. #endif
  7201.     if (te.hModule == (HMODULE)hModule)
  7202.         return ((WINHAND)te.hTask);
  7203.     if (te.hInst == (HINSTANCE)hModule)
  7204.         return ((WINHAND)te.hTask);
  7205.     brc = TaskNext (&te);
  7206.     }
  7207. #endif
  7208.     return (0);
  7209. }
  7210.     
  7211.     
  7212.  
  7213.  
  7214. /*
  7215.  * Register a file deletion operation when hTask goes away.
  7216.  */
  7217. int        
  7218. mswin_ontask_del (WINHAND hTask, char *path)
  7219. {
  7220.     OnTaskItem        *ot;
  7221.     BOOL        wasEmpty;
  7222.     
  7223.     ot = MemAlloc (sizeof (OnTaskItem));
  7224.     if (ot == NULL)
  7225.     return (-1);
  7226.  
  7227.     wasEmpty = (gOnTaskList == NULL);
  7228.     ot->hTask = (HTASK) hTask;
  7229.     strncpy (ot->path, path, PATH_MAX);
  7230.     ot->path[PATH_MAX] = '\0';
  7231.     ot->next = gOnTaskList;
  7232.     gOnTaskList = ot;
  7233.     MyTimerSet ();
  7234.     return (0);
  7235. }
  7236.  
  7237.  
  7238. /*
  7239.  * Execute command and wait for the 
  7240.  */
  7241. int
  7242. mswin_exec_and_wait (char *whatsit, char *command)
  7243. {
  7244.     MEvent        mouse;
  7245.     BOOL        brc;
  7246.     int            rc;
  7247.     char        waitingFor[256];
  7248. #ifdef    WIN32
  7249.     STARTUPINFO        start_info;
  7250.     PROCESS_INFORMATION    proc_info;
  7251.     DWORD        exit_code;
  7252.  
  7253.     mswin_flush ();
  7254.  
  7255.     memset(&proc_info, 0, sizeof(proc_info));
  7256.     memset(&start_info, 0, sizeof(start_info));
  7257.     start_info.dwFlags        = STARTF_FORCEONFEEDBACK;
  7258.     start_info.wShowWindow  = SW_SHOWNORMAL;
  7259.  
  7260.     if(CreateProcess(NULL, command, NULL, NULL, FALSE,
  7261.              CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
  7262.              NULL, NULL, &start_info, &proc_info) == TRUE){
  7263.  
  7264.     sprintf (waitingFor, "%s is currently waiting for the %s (%s) to complete.  Click \"Cancel\" to stop waiting, or \"OK\" to continue waiting.",
  7265.          gszAppName, whatsit, command);
  7266.  
  7267.     /*
  7268.      * Go into holding pattern until the other application terminates
  7269.      * or we are told to stop waiting.
  7270.      */
  7271.     while(GetExitCodeProcess(proc_info.hProcess, &exit_code) == TRUE){
  7272.         if(exit_code == STILL_ACTIVE){
  7273.         rc = mswin_getc();
  7274.         brc = mswin_getmouseevent (&mouse);
  7275.  
  7276.         if (rc != MSWIN_KEY_NODATA || 
  7277.             (brc && mouse.event == M_EVENT_DOWN)) {
  7278.  
  7279.             rc = MessageBox (ghTTYWnd, waitingFor, whatsit, 
  7280.                      MB_ICONSTOP | MB_OKCANCEL);
  7281.             SelClear ();
  7282.             if (rc == IDCANCEL){
  7283.             /* terminate message to child ? */
  7284.             return (-2);
  7285.             }
  7286.         }
  7287.         }
  7288.         else{
  7289.         /* do something about child's exit status */
  7290.         break;
  7291.         }
  7292.     }
  7293.  
  7294.     if (gpTTYInfo->fMinimized) 
  7295.       ShowWindow (ghTTYWnd, SW_SHOWNORMAL);
  7296.  
  7297.     BringWindowToTop (ghTTYWnd);
  7298.     return (0);
  7299.     }
  7300.     else{
  7301.     return((rc = (int) GetLastError()) ? rc : -1);        /* hack */
  7302.     }
  7303. #else
  7304.     HTASK    hTask;
  7305.     UINT    urc;
  7306.     
  7307.     
  7308.     mswin_flush ();
  7309.     
  7310.     urc = WinExec (command, SW_SHOW);
  7311. #ifdef FDEBUG
  7312.     if (mswin_debug >= 8) {
  7313.     fprintf (mswin_debugfile, "mswin_exec_and_wait:  command '%s'\n", command);
  7314.     fprintf (mswin_debugfile, "                      WinExec returns module x%x\n",
  7315.         urc);
  7316.     }
  7317. #endif
  7318.  
  7319.     if (urc < 32) 
  7320.     return ((int)urc);
  7321.  
  7322.     hTask = (HTASK) mswin_inst2task (urc);
  7323.  
  7324. #ifdef FDEBUG
  7325.     if (mswin_debug >= 8) 
  7326.     fprintf (mswin_debugfile, "mswin_exec_and_wait:  module maps to task x%x, wait for it to finish\n",
  7327.         (UINT) hTask);
  7328. #endif
  7329.  
  7330.     if (hTask == NULL)
  7331.     return (-1);
  7332.     
  7333.     sprintf (waitingFor, "%s is currently waiting for the %s (%s) to complete.  Click \"Cancel\" to stop waiting, or \"OK\" to continue waiting.",
  7334.         gszAppName, whatsit, command);
  7335.     
  7336.  
  7337.     /*
  7338.      * Go into holding pattern until the other application terminates
  7339.      * or we are told to stop waiting.
  7340.      */
  7341.     while (IsTask (hTask)) {
  7342.     rc = mswin_getc();
  7343.     brc = mswin_getmouseevent (&mouse);
  7344.  
  7345.     if (rc != MSWIN_KEY_NODATA || 
  7346.         (brc && mouse.event == M_EVENT_DOWN)) {
  7347.     
  7348.         rc = MessageBox (ghTTYWnd, waitingFor, whatsit, 
  7349.             MB_ICONSTOP | MB_OKCANCEL);
  7350.         SelClear ();
  7351.         if (rc == IDCANCEL)
  7352.          return (-2);
  7353.     }
  7354.     }
  7355.     if (gpTTYInfo->fMinimized) 
  7356.     ShowWindow (ghTTYWnd, SW_SHOWNORMAL);
  7357.     BringWindowToTop (ghTTYWnd);
  7358.     return (0);
  7359. #endif
  7360. }
  7361.  
  7362.  
  7363.  
  7364.  
  7365. /*
  7366.  * Generate an error message for a failed windows exec or loadlibrary.
  7367.  */
  7368. void
  7369. mswin_exec_err_msg (char *what, int status, char *buf, int buflen)
  7370. {
  7371.     switch (status) {
  7372.     case 2:
  7373.     case 3:
  7374.     wsprintf (buf, "%s not found.", what);
  7375.     break;
  7376.     
  7377.     case 8:
  7378.     wsprintf (buf, "Not enough memory to run %s.", what);
  7379.     break;
  7380.     
  7381.     default:
  7382.     wsprintf (buf, "Error %d starting %s.", status, what);
  7383.     break;
  7384.     }
  7385. }
  7386.  
  7387.         
  7388.  
  7389.  
  7390.  
  7391.  
  7392. LOCAL void
  7393. ProcessOnTask (void)
  7394. {
  7395.     OnTaskItem        *ot, *pot, *not;
  7396.     BOOL        wasEmpty, isRunning;
  7397.     static BOOL        InOnTask = FALSE;
  7398. #ifdef    WIN32
  7399.     DWORD        exit_code;
  7400. #endif
  7401.     
  7402.     if (gOnTaskList == NULL) 
  7403.     return;
  7404.  
  7405.     if (InOnTask)
  7406.     return;
  7407.     InOnTask = TRUE;
  7408.  
  7409.     /* Scann through list. */
  7410.     wasEmpty = (gOnTaskList == NULL);
  7411.     ot = gOnTaskList;
  7412.     while (ot != NULL) {
  7413.     not = ot->next;
  7414.     
  7415.     /* If hTask == NULL that indicates an action for when we exit.
  7416.      * otherwise hTask is the handle for some other task.
  7417.      * If we are exiting, or the other task is gone, perform the action
  7418.      */
  7419. #ifdef    WIN32
  7420.     if((isRunning = GetExitCodeProcess (ot->hTask, &exit_code))
  7421.        && exit_code != STILL_ACTIVE)
  7422.       isRunning = FALSE;
  7423. #else
  7424.     isRunning = !IsTask (ot->hTask);
  7425. #endif
  7426.     if (!isRunning) {
  7427.  
  7428.         /* Perform action.*/
  7429.         unlink (ot->path);
  7430.         
  7431.         /* Remove item. */
  7432.         if (ot == gOnTaskList) {
  7433.         /* Remve from head of list. */
  7434.         gOnTaskList = not;
  7435.         } else {
  7436.         /* Remove from middle of list - find previous. */
  7437.         for (pot = gOnTaskList; pot != NULL && pot->next != ot; 
  7438.                             pot = pot->next);
  7439.         if (pot != NULL)                     
  7440.             pot->next = not;
  7441.         }
  7442.         MemFree (ot);
  7443.         }
  7444.         
  7445.     ot = not;
  7446.     }
  7447.     MyTimerSet ();
  7448.     InOnTask = FALSE;
  7449. }
  7450.  
  7451.  
  7452.  
  7453.  
  7454.  
  7455.  
  7456. /*
  7457.  * Register a file deletion operation when hTask goes away.
  7458.  */
  7459. int        
  7460. mswin_onexit_del (char *path)
  7461. {
  7462.     OnTaskItem        *ot;
  7463.     BOOL        wasEmpty;
  7464.     
  7465.     ot = MemAlloc (sizeof (OnTaskItem));
  7466.     if (ot == NULL)
  7467.     return (-1);
  7468.  
  7469.     ot->hTask = NULL;
  7470.     strncpy (ot->path, path, PATH_MAX);
  7471.     ot->path[PATH_MAX] = '\0';
  7472.     ot->next = gOnExitList;
  7473.     gOnExitList = ot;
  7474.     return (0);
  7475. }
  7476.  
  7477.  
  7478.  
  7479.  
  7480.  
  7481.  
  7482. /*
  7483.  * Called when exiting.  Perform any on-exit actions.
  7484.  *
  7485.  * (This was originally implemented to delete temp files that got left
  7486.  *  around when the user ended the windows session, which closed pine
  7487.  *  with no shutdown.  See WM_ENDSESSION.)
  7488.  */
  7489. LOCAL void
  7490. ProcessOnExit (void)
  7491. {
  7492.     OnTaskItem        *ot, *pot, *not;
  7493.     static BOOL        InOnExit = FALSE;
  7494.     
  7495.     if (gOnExitList == NULL) 
  7496.     return;
  7497.  
  7498.     if (InOnExit)
  7499.     return;
  7500.     InOnExit = TRUE;
  7501.  
  7502.     /* Scann through list. */
  7503.     ot = gOnExitList;
  7504.     while (ot != NULL) {
  7505.     not = ot->next;
  7506.     
  7507.     /* Perform action.*/
  7508.     unlink (ot->path);
  7509.  
  7510.     /* Remove item (always from head). */
  7511.     gOnExitList = not;
  7512.     MemFree (ot);
  7513.     ot = not;
  7514.     }
  7515.     InOnExit = FALSE;
  7516. }
  7517.  
  7518.  
  7519.  
  7520. int
  7521. mswin_set_quit_confirm (int confirm)
  7522. {
  7523.     gConfirmExit = (confirm != 0);
  7524.     return (confirm);
  7525. }
  7526.  
  7527.  
  7528.  
  7529. /*
  7530.  * Called when Windows is in shutting down.  Before actually shutting down
  7531.  * Windows goes around to all the applications and asks if it is OK with
  7532.  * them to shut down (WM_QUERYENDSESSION).  
  7533.  * If gConfirmExit is set, ask the user if they want to exit.
  7534.  * Returning zero will stop the shutdown, non-zero allows it to proceed.
  7535.  */
  7536. LOCAL LRESULT
  7537. ConfirmExit (void)
  7538. {
  7539.     char    msg[256];
  7540.     int        rc;
  7541.     
  7542.     if (gConfirmExit) {
  7543.     sprintf (msg, "Exiting may cause you to loose work in %s, Exit?",
  7544.         gszAppName);
  7545.     rc = MessageBox (ghTTYWnd, msg, gszAppName, 
  7546.         MB_ICONSTOP | MB_OKCANCEL);
  7547.     if (rc == IDCANCEL)
  7548.         return (0);
  7549.     }
  7550.     return (1);
  7551. }
  7552.  
  7553.          
  7554.  
  7555.  
  7556.  
  7557. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  7558.  *
  7559.  *                  Text display Windows.
  7560.  *
  7561.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  7562. #define TW_TEXTBLOCK    1
  7563. #define TW_TEXTLINES    2
  7564.  
  7565.  
  7566. /*
  7567.  * TextWndInfo is used to keep track of each text window.
  7568.  *
  7569.  * Selections:
  7570.  *  The "dot" and the "mark" are used for the selection.  When the user
  7571.  *  pushes the mouse button down that sets the "dot".  As the user
  7572.  *  drags the mouse across text, that moves the "mark" Text between the
  7573.  *  two points is the selection.  dot and mark are not orderd.  The
  7574.  *  selection starts with the character pointed to by the first, and
  7575.  *  ends BEFORE the character pointed to be the second.
  7576.  *
  7577.  *  Each line has a logical line terminator character.  When the
  7578.  *  selection ends at the end of a line, the logical line terminator is
  7579.  *  NOT included When the selection ends at the beginning of the next
  7580.  *  line, the logical line terminator IS included.  For text with lines
  7581.  *  0 to N, a selection ending at line N+1, character 0 would include
  7582.  *  the last line and its logical line terminator.
  7583.  *
  7584.  */
  7585.  
  7586. typedef struct text_wnd_info {
  7587.     char    *text;        /* Pointer to big block of text. */
  7588.     char    **lines;    /* Pointer to array of line starts. */
  7589.     UINT    lineCount;    /* Count of lines. */
  7590.     int        textAs;        /* How text stored in memory. */
  7591.     int        flags;        /* Flag special behavior. */
  7592.     long    curLine;    /* Current line (scroll position). */
  7593.     int        xChar, yChar;    /* Size of a character. */
  7594.     int        xSize, ySize;    /* Window size. */
  7595.     int        nRows;        /* Number of rows fit on screen. */
  7596.     int        nCols;        /* Number of columns fit on screen. */
  7597.     long    dotLine;    /* Line on which dot is located. */
  7598.     long    dotChar;    /* Char in line on which dot is located. */
  7599.     long    markLine;    /* Line on which mark is located. */
  7600.     long    markChar;    /* Char in line on which mark is located. */
  7601.     BOOL    tracking;    /* TRUE when tracking mouse. */
  7602.     int        scrollDirect;    /* Direction to scroll. */
  7603.     HFONT    hFont;        /* Font in use. */
  7604.     DWORD    rgbFGColor;    /* Normal forground color. */
  7605.     DWORD    rgbBGColor;    /* Normal background color. */
  7606.     DWORD    rgbRFGColor;    /* Reverse forground color. */
  7607.     DWORD    rgbRBGColor;    /* Reverse background color */
  7608. } TextWndInfo;
  7609.  
  7610.  
  7611.  
  7612.  
  7613.  
  7614. #define TWS_UP        -1
  7615. #define TWS_OFF        0
  7616. #define TWS_DOWN    1
  7617. #define TWS_TIMERID    1
  7618. #define TWS_TIMEOUT    50
  7619.  
  7620.  
  7621. /*
  7622.  * Free text data associated with a TextWindInfo structure, but not the
  7623.  * structure itself.
  7624.  */
  7625. LOCAL void
  7626. TWFreeData (TextWndInfo *ptwInfo)
  7627. {
  7628.     char **l;
  7629.     
  7630.     if (!(ptwInfo->flags & MSWIN_DT_NODELETE)) {
  7631.     if (ptwInfo->textAs == TW_TEXTBLOCK) 
  7632.         MemFree (ptwInfo->text);
  7633.     else {
  7634.         for (l = ptwInfo->lines; *l != NULL; ++l)
  7635.         MemFree (*l);
  7636.     }
  7637.     MemFree (ptwInfo->lines);
  7638.     }
  7639. }
  7640.  
  7641.  
  7642.     
  7643.     
  7644.     
  7645.     
  7646. /*
  7647.  * Show a help message.
  7648.  * Help text comes as a null terminated array of pointers to lines of 
  7649.  * text.  Stuff these into a buffer and pass that to MessageBox.
  7650.  */
  7651. void
  7652. mswin_showhelpmsg (WINHAND wnd, char **helplines)
  7653. {
  7654.     char    **l;
  7655.     char    *helptext;
  7656.     int        buflen;
  7657.     HWND    hWnd;
  7658.     
  7659.     hWnd = (HWND) wnd;
  7660.     if (hWnd == NULL) 
  7661.     hWnd = ghTTYWnd;
  7662.     
  7663.     
  7664.     buflen = 0;
  7665.     for (l = helplines; *l != NULL; ++l) 
  7666.     buflen += lstrlen (*l);
  7667.  
  7668.     helptext = MemAlloc (buflen + 1);
  7669.     if (helptext == NULL)
  7670.     return;
  7671.     *helptext = '\0';
  7672.     for (l = helplines; *l != NULL; ++l)
  7673.     strcat (helptext, *l);   
  7674.  
  7675.     MessageBox (hWnd, helptext, "Help", 
  7676.         MB_APPLMODAL | MB_ICONINFORMATION | MB_OK);
  7677.     MemFree (helptext);
  7678. }
  7679.  
  7680.     
  7681.  
  7682.  
  7683.  
  7684.  
  7685. /*
  7686.  * Display text in a window.
  7687.  *
  7688.  * Parameters:
  7689.  *    title        - Title of window.
  7690.  *    pText        - address of text to display.
  7691.  *    textLen        - Length of text, in bytes.  Limited to 64K.
  7692.  *    pLines        - Array of pointers to lines of text.  Each
  7693.  *              line is a sepreate allocation block.  The
  7694.  *              entry in the array of pointers should be a 
  7695.  *              NULL.
  7696.  *              
  7697.  * The text can be supplied as a buffer (pText and textLen) in which
  7698.  * lines are terminated by CRLF (including the last line in buffer).
  7699.  * Or it can be supplied as a NULL terminated array of pointers to
  7700.  * lines.  Each entry points to a seperatly allocated memory block
  7701.  * containing a null terminated string.
  7702.  *
  7703.  * If the function succeeds the memory containing the text will be
  7704.  * used until the user closes the window, at which point it will be
  7705.  * freed.
  7706.  *
  7707.  * Returns:
  7708.  *    handle to the created window - SUCCESS
  7709.  *    -1                 - Failed.
  7710.  */ 
  7711. int
  7712. mswin_displaytext (char *title, char *pText, size_t textLen, char **pLines, 
  7713.     int windRef, int flags)
  7714. {
  7715.     TextWndInfo        *ptwInfo;
  7716.     HWND        hWnd;
  7717.     HDC            hDC;
  7718.     TEXTMETRIC        tm;
  7719.     char        *p;
  7720.     char        **l;
  7721.     UINT        lineCount;
  7722.     int            textAs;
  7723.     UINT        i;
  7724.     RECT        rSize;
  7725.     DWORD        dwStyle;
  7726.     
  7727.  
  7728.     if (pText == NULL && pLines == NULL)
  7729.     return (-1);
  7730.  
  7731.     /* 
  7732.      * How was text supplied?
  7733.      */
  7734.     if (pLines != NULL) {
  7735.         
  7736.     /* Array of pointers to lines supplied. Count lines. */
  7737.     lineCount = 0;
  7738.     for (l = pLines; *l != NULL; ++l)
  7739.         ++lineCount;
  7740.     if (lineCount == 0)
  7741.         return (-1);
  7742.         textAs = TW_TEXTLINES;
  7743.     }
  7744.     else {
  7745.         
  7746.     /* Pointer to block of text supplied. */
  7747.     if (textLen == 0)
  7748.         return (-1);
  7749.     lineCount = 0;
  7750.     for (p = pText+1, i = textLen - 1; i > 0; ++p, --i) {
  7751.         if (*(p-1) == ASCII_CR && *p == ASCII_LF) 
  7752.         ++lineCount;
  7753.     }
  7754.  
  7755.     if (lineCount == 0) 
  7756.         return (-1);
  7757.  
  7758.  
  7759.     pLines = (char **) MemAlloc (sizeof (char *) * (lineCount+1));
  7760.     if (pLines == NULL) 
  7761.         return (-1);
  7762.  
  7763.  
  7764.     /* Fill the lines array. */
  7765.     l = pLines;
  7766.     *l = pText;
  7767.     for (p = pText+1, i = textLen - 1; i > 0; ++p, --i) {
  7768.         if (*(p-1) == ASCII_CR && *p == ASCII_LF) {
  7769.         *(p-1) = '\0';
  7770.         *(++l) = p+1;
  7771.         }
  7772.     }
  7773.     
  7774.     /* Add a NULL terminator just for form. */
  7775.     *(pLines + lineCount) = NULL;
  7776.  
  7777.     textAs = TW_TEXTBLOCK;
  7778.     }
  7779.  
  7780.     
  7781.     /* Was a valid existing window supplied? */
  7782.     if (IsWindow((HWND)windRef)) {
  7783.     /* Get associated structure. */
  7784.     ptwInfo = (TextWndInfo *) GetWindowLong ((HWND)windRef, GWL_PTEXTINFO);
  7785.     if (ptwInfo != NULL) 
  7786.         hWnd = (HWND) windRef;    /* Valid window. */
  7787.     else
  7788.         windRef = 0;        /* Invalid window. */
  7789.     }
  7790.     else 
  7791.     windRef = 0;            /* Invalid window. */
  7792.     
  7793.  
  7794.     /* Allocate a control structrue for window, or free contents of
  7795.      * existing structure. */
  7796.     if (windRef == 0) {
  7797.     ptwInfo = (TextWndInfo *) MemAlloc (sizeof (TextWndInfo));
  7798.     if (ptwInfo == NULL) {
  7799.         if (textAs == TW_TEXTBLOCK)
  7800.         MemFree (pLines);
  7801.         return (-1);
  7802.     }
  7803.     memset (ptwInfo, 0, sizeof (TextWndInfo));
  7804.     }
  7805.     else {
  7806.     TWFreeData (ptwInfo);
  7807.     ptwInfo->dotLine = 0;
  7808.     ptwInfo->dotChar = 0;
  7809.     ptwInfo->markLine = 0;
  7810.     ptwInfo->markChar = 0;
  7811.     ptwInfo->tracking = FALSE;
  7812.     }
  7813.     
  7814.     
  7815.     
  7816.     ptwInfo->flags = flags;
  7817.     ptwInfo->text = pText;
  7818.     ptwInfo->lines = pLines;
  7819.     ptwInfo->lineCount = lineCount;
  7820.     ptwInfo->textAs = textAs;
  7821.     ptwInfo->curLine = 0;
  7822.  
  7823.  
  7824.     /* Create a new window or use existing. */
  7825.     if (windRef == 0) {
  7826.     rSize.left = 0;
  7827.     rSize.right = (MARGINE_LEFT * 2) + (gpTTYInfo->xChar * 80);
  7828.     rSize.top = 0;
  7829.     rSize.bottom = gpTTYInfo->ySize;
  7830.     dwStyle = WS_OVERLAPPEDWINDOW | WS_VSCROLL;
  7831.     AdjustWindowRect (&rSize, dwStyle, TRUE);
  7832.     rSize.right += 16;
  7833.     hWnd = CreateWindow (gszTextClass, title,
  7834.                dwStyle,
  7835.                CW_USEDEFAULT, CW_USEDEFAULT,
  7836.                rSize.right - rSize.left, rSize.bottom - rSize.top,
  7837.                HWND_DESKTOP, NULL, ghInstance, ptwInfo);
  7838.  
  7839.  
  7840.     if (hWnd == NULL) {
  7841.         MemFree (ptwInfo);
  7842.         if (textAs == TW_TEXTBLOCK)
  7843.         MemFree (pLines);
  7844.         return (-1);
  7845.     }
  7846.     ptwInfo->hFont = gpTTYInfo->hTTYFont;
  7847.  
  7848.     hDC = GetDC (hWnd);
  7849.     SelectObject (hDC, ptwInfo->hFont);
  7850.     GetTextMetrics (hDC, &tm);
  7851.     ReleaseDC (hWnd, hDC);
  7852.     ptwInfo->xChar = tm.tmAveCharWidth;
  7853.     ptwInfo->yChar = tm.tmHeight + tm.tmExternalLeading;
  7854.  
  7855.     ptwInfo->rgbFGColor = gpTTYInfo->rgbFGColor;    
  7856.     ptwInfo->rgbBGColor = gpTTYInfo->rgbBGColor;    
  7857.     ptwInfo->rgbRFGColor = gpTTYInfo->rgbRFGColor;
  7858.     ptwInfo->rgbRBGColor = gpTTYInfo->rgbRBGColor;
  7859.     }
  7860.     else {
  7861.     /* Invalidate whole window, change title, and move to top. */
  7862.     InvalidateRect (hWnd, NULL, TRUE);
  7863.     SetWindowText (hWnd, title);
  7864.     SetWindowPos (hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  7865.         SetScrollPos (hWnd, SB_VERT,  (int)(gpTTYInfo->scrollPos = 0L), TRUE);
  7866.     }
  7867.     
  7868.     
  7869.     SetWindowLong (hWnd, GWL_PTEXTINFO, (LPARAM) ptwInfo);
  7870.     SetScrollRange (hWnd, SB_VERT, 0, (int)ptwInfo->lineCount - 1, FALSE);
  7871.     SetScrollPos (hWnd, SB_VERT, 0, FALSE);
  7872.  
  7873.     ShowWindow (hWnd, SW_SHOW);
  7874.     UpdateWindow (hWnd);
  7875.     return ((int)hWnd);
  7876. }
  7877.  
  7878.  
  7879.  
  7880.  
  7881.  
  7882.  
  7883. LRESULT FAR PASCAL __export 
  7884. TWWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  7885. {
  7886.     TextWndInfo        *ptwInfo;
  7887.     char        **l;
  7888.     
  7889.     
  7890.     switch (uMsg) {
  7891.     case WM_CREATE:
  7892.     break;
  7893.     
  7894.     case WM_COMMAND:
  7895.     switch ((WORD) wParam) {
  7896.     case IDM_FILE_CLOSE:
  7897.         DestroyWindow (hWnd);
  7898.         break;
  7899.         
  7900.     case IDM_FILE_PRINT:
  7901.         TWPrint (hWnd);
  7902.         break;
  7903.         
  7904.     case IDM_EDIT_COPY:
  7905.         TWEditCopy (hWnd);
  7906.         break;
  7907.  
  7908.     default:
  7909.         return (DefWindowProc (hWnd, uMsg, wParam, lParam));
  7910.         }
  7911.     break;
  7912.         
  7913.      
  7914.     case WM_VSCROLL:
  7915. #ifdef    WIN32
  7916.     TWScroll (hWnd, LOWORD(wParam), HIWORD(wParam));
  7917. #else
  7918.     TWScroll (hWnd, wParam, LOWORD (lParam));
  7919. #endif
  7920.     break;
  7921.     
  7922.     case WM_KEYDOWN:
  7923.     if (TWKeyDown (hWnd, LOBYTE (wParam), (DWORD)lParam))
  7924.         return (0);
  7925.         return( DefWindowProc( hWnd, uMsg, wParam, lParam ) ) ;
  7926.     
  7927.     case WM_LBUTTONDOWN:
  7928.     TWMouseDown (hWnd, 1, LOWORD (lParam), HIWORD (lParam), wParam);
  7929.     break;
  7930.  
  7931.     case WM_LBUTTONUP:
  7932.     TWMouseUp (hWnd, 1, LOWORD (lParam), HIWORD (lParam), wParam);
  7933.     break;
  7934.  
  7935.     case WM_MOUSEMOVE:
  7936.     TWMouseTrack (hWnd, LOWORD (lParam), HIWORD (lParam));
  7937.     break;
  7938.  
  7939.     case WM_ERASEBKGND:
  7940.     TWErase (hWnd, (HDC) wParam);
  7941.     break;
  7942.     
  7943.     case WM_PAINT:
  7944.     TWPaint (hWnd);
  7945.     break;
  7946.  
  7947.     case WM_SIZE:
  7948.     TWSetSize (hWnd, wParam, HIWORD(lParam), LOWORD(lParam));
  7949.         break ;
  7950.     
  7951.     case WM_TIMER:
  7952.     TWScrollTimer (hWnd);
  7953.     break;
  7954.     
  7955.     case WM_CLOSE:
  7956.     DestroyWindow (hWnd);
  7957.     break;
  7958.     
  7959.     case WM_DESTROY:
  7960.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  7961.     if (ptwInfo != NULL) {
  7962.         TWFreeData (ptwInfo);
  7963.         MemFree (ptwInfo);
  7964.         }
  7965.     break;
  7966.      
  7967.     default:
  7968.         return (DefWindowProc (hWnd, uMsg, wParam, lParam));
  7969.     }
  7970.     return (0);
  7971. }
  7972.  
  7973.  
  7974.  
  7975. LOCAL BOOL
  7976. TWErase (HWND hWnd, HDC hDC)
  7977. {
  7978.     RECT        erect;
  7979.     HBRUSH        hBrush;
  7980.     TextWndInfo        *ptwInfo;
  7981.  
  7982.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  7983.     if (ptwInfo == NULL) 
  7984.     return (FALSE);
  7985.     
  7986.  
  7987.     GetClientRect (hWnd, &erect);
  7988.     hBrush = CreateSolidBrush (ptwInfo->rgbBGColor);
  7989.     if (hBrush != NULL) {
  7990.     FillRect (hDC, &erect, hBrush);
  7991.     DeleteObject (hBrush);
  7992.     }
  7993.     return (TRUE);
  7994. }
  7995.  
  7996.  
  7997.  
  7998. LOCAL void
  7999. TWPaint (HWND hWnd)
  8000. {
  8001.     TextWndInfo        *ptwInfo;
  8002.     PAINTSTRUCT        ps;
  8003.     HDC            hDC;
  8004.     HFONT        hOldFont;
  8005.     HBRUSH        hBrush;
  8006.     int            nRow, nEndRow;        /* screen row being painted.*/
  8007.     int            nCol;            /* position in current line */
  8008.     long        nLine;            /* Line number being painted*/
  8009.     char        *text;            /* text being painted. */
  8010.     RECT        rect;            /* Rect surrounding line. */
  8011.     int            lineLen;        /* # chars in line. */
  8012.     int            writeLen;        /* # chars being painted. */
  8013.     UINT        topLine;
  8014.     int            nVertPos;
  8015.     BOOL        selend;
  8016.     long        selStartLine, selEndLine;
  8017.     long        selStartChar, selEndChar;
  8018.     
  8019.     
  8020.     /* If I got the window set up right I don't expect to be called to
  8021.      * paint the ICON, but... */
  8022.     if (IsIconic (hWnd))
  8023.     return;
  8024.     
  8025.    
  8026.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  8027.     if (ptwInfo == NULL) 
  8028.     return;
  8029.  
  8030.  
  8031.     /* Scroll Position is top line in window */
  8032.     topLine = ptwInfo->curLine;
  8033.     
  8034.     
  8035.     hDC = BeginPaint (hWnd, &ps);
  8036.     
  8037.     
  8038.     hOldFont = SelectObject (hDC, ptwInfo->hFont);
  8039.     SetTextColor (hDC, ptwInfo->rgbFGColor);
  8040.     SetBkColor (hDC, ptwInfo->rgbBGColor);
  8041.     SetBkMode (hDC, OPAQUE);
  8042.     
  8043.     /* Get the Paint rectange and calculate start and end rows. */
  8044.     rect = ps.rcPaint;
  8045.     nRow = max (0, (rect.top - MARGINE_TOP) / ptwInfo->yChar);
  8046.     nEndRow = max (0, (rect.bottom - MARGINE_TOP - 1) / ptwInfo->yChar);
  8047.     nCol = 0;
  8048.     
  8049.     
  8050.     /* Order the dot and mark. */
  8051.     if (ptwInfo->dotLine < ptwInfo->markLine || 
  8052.         (ptwInfo->dotLine == ptwInfo->markLine  &&
  8053.          ptwInfo->dotChar < ptwInfo->markChar)) {
  8054.     selStartLine = ptwInfo->dotLine;
  8055.     selStartChar = ptwInfo->dotChar;
  8056.     selEndLine = ptwInfo->markLine;
  8057.     selEndChar = ptwInfo->markChar;
  8058.     }
  8059.     else {
  8060.     selStartLine = ptwInfo->markLine;
  8061.     selStartChar = ptwInfo->markChar;
  8062.     selEndLine = ptwInfo->dotLine;
  8063.     selEndChar = ptwInfo->dotChar;
  8064.     }
  8065.     
  8066.     
  8067.     /*
  8068.      * xxx erase top and left margine.
  8069.      */
  8070.  
  8071.  
  8072.     for (; nRow <= nEndRow && topLine + nRow < ptwInfo->lineCount; ) {
  8073.         
  8074.     /* Calculate the position of this line. */
  8075.     nLine = topLine + nRow;
  8076.     text = *(ptwInfo->lines + nLine);
  8077.     lineLen = strlen (text);
  8078.     
  8079.     /* 
  8080.      * Calculate the run length of this write.  run length extends
  8081.      * to the next change in selection or (usualy) the end of the 
  8082.      * line. 
  8083.      */
  8084.     selend = FALSE;
  8085.     writeLen = lineLen - nCol;
  8086.     if (selEndLine == nLine && selEndChar > nCol) {
  8087.         writeLen = selEndChar - nCol;
  8088.         selend = TRUE;
  8089.         }
  8090.     if (selStartLine == nLine && selStartChar > nCol) 
  8091.         writeLen = selStartChar - nCol;
  8092.  
  8093.     
  8094.     /*
  8095.      * Calculate the bounding rectangle.  
  8096.      * When the text includes the end of the line the bounding
  8097.      * rectange extends to the right side of the window so that the
  8098.      * end of the line gets drawn with the correct colors.
  8099.      * The exception is when the selection ends at the end of the line.
  8100.      * This special case is also handled below.
  8101.      */
  8102.     nVertPos = (nRow * ptwInfo->yChar) + MARGINE_TOP;
  8103.     rect.top = nVertPos;
  8104.     rect.bottom = min (nVertPos + ptwInfo->yChar, 
  8105.                 ptwInfo->ySize - FRAME_3D_SIZE);
  8106.     rect.left = (nCol * ptwInfo->xChar) + MARGINE_LEFT;
  8107.     if (nCol + writeLen >= lineLen && !selend) 
  8108.         rect.right = ptwInfo->xSize - FRAME_3D_SIZE;
  8109.         else
  8110.         rect.right = ((nCol + writeLen) * ptwInfo->xChar) + MARGINE_LEFT;
  8111.     
  8112.     
  8113.  
  8114.     /*
  8115.      * Select normal or inverted colors.
  8116.      */
  8117.     if ((nLine > selStartLine || 
  8118.             (nLine == selStartLine && nCol >= selStartChar)) && 
  8119.         (nLine < selEndLine ||
  8120.             (nLine == selEndLine && nCol < selEndChar))) {
  8121.         /* Inverted. */
  8122.         SetTextColor (hDC, ptwInfo->rgbRFGColor);
  8123.         SetBkColor (hDC, ptwInfo->rgbRBGColor);
  8124.     }
  8125.     else {
  8126.         /* Normal. */
  8127.         SetTextColor (hDC, ptwInfo->rgbFGColor);
  8128.         SetBkColor (hDC, ptwInfo->rgbBGColor);
  8129.     }
  8130.  
  8131.     
  8132.     /*
  8133.      * Draw the text.
  8134.      */
  8135.     ExtTextOut (hDC, rect.left, nVertPos, ETO_OPAQUE | ETO_CLIPPED, 
  8136.         &rect, text+nCol, writeLen, NULL);
  8137.     
  8138.     
  8139.     /*
  8140.      * If the selection ends at the end of a line I need to erase
  8141.      * the blank space after the line.
  8142.      */
  8143.     if (selend) {
  8144.         rect.left = ((nCol + lineLen) * ptwInfo->xChar) + MARGINE_LEFT;
  8145.         rect.right = ptwInfo->xSize - FRAME_3D_SIZE;
  8146.         hBrush = CreateSolidBrush (ptwInfo->rgbBGColor);
  8147.         if (hBrush != NULL) {
  8148.             FillRect (hDC, &rect, hBrush);
  8149.             DeleteObject (hBrush);
  8150.         }
  8151.         }
  8152.         
  8153.     
  8154.     nCol += writeLen;
  8155.     if (nCol >= lineLen) {
  8156.        ++nRow;
  8157.        nCol = 0;
  8158.     }
  8159.     }
  8160.     
  8161.     
  8162.     /* Erase any section of the screen that did not have a line draw
  8163.      * on it. */
  8164.     if (nRow <= nEndRow) {
  8165.     rect.top = (nRow * ptwInfo->yChar) + MARGINE_TOP;
  8166.     rect.right = FRAME_3D_SIZE;
  8167.     rect.left = ptwInfo->xSize - FRAME_3D_SIZE;
  8168.     rect.bottom = ptwInfo->ySize - FRAME_3D_SIZE;
  8169.     FillRectColor (hDC, &rect, ptwInfo->rgbBGColor);
  8170.     }
  8171.     
  8172.     
  8173.     
  8174.     /* In Windows 95 draw an inset 3d frame. */
  8175.     if (gUse3DFrame) {
  8176.     rect.top = 0;
  8177.     rect.bottom = ptwInfo->ySize;
  8178.     rect.left = 0;
  8179.     rect.right = ptwInfo->xSize;
  8180.     FrameRect3D (hDC, &rect, FRAME_3D_SIZE, FALSE);
  8181.     }
  8182.     
  8183.     
  8184.     
  8185.     
  8186.     SelectObject (hDC, hOldFont);
  8187.     EndPaint (hWnd, &ps);
  8188.     return;
  8189. }
  8190.  
  8191.  
  8192.  
  8193. /*
  8194.  * Scroll the text window.
  8195.  */
  8196. LOCAL void
  8197. TWScroll (HWND hWnd, int wScrollCode, int nPos)
  8198. {
  8199.     TextWndInfo        *ptwInfo;
  8200.     BOOL        fRepaint;
  8201.     RECT        rect;
  8202.  
  8203.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  8204.     if (ptwInfo == NULL) 
  8205.     return;
  8206.  
  8207.     rect.top = 0 + FRAME_3D_SIZE;
  8208.     rect.bottom =  ptwInfo->ySize - FRAME_3D_SIZE;
  8209.     rect.left = 0 + FRAME_3D_SIZE;
  8210.     rect.right = ptwInfo->xSize - FRAME_3D_SIZE;
  8211.  
  8212.  
  8213.  
  8214.     fRepaint = FALSE;
  8215.     
  8216.     switch (wScrollCode) {
  8217.     case SB_BOTTOM:
  8218.     ptwInfo->curLine = ptwInfo->lineCount - 1;
  8219.     fRepaint = TRUE;
  8220.     break;
  8221.     
  8222.     case SB_TOP:
  8223.     ptwInfo->curLine = 0;
  8224.     fRepaint = TRUE;
  8225.     break;
  8226.     
  8227.     case SB_LINEDOWN:
  8228.     if (ptwInfo->curLine < ptwInfo->lineCount - 1) {
  8229.         ++ptwInfo->curLine;
  8230.         ScrollWindow (hWnd, 0, -ptwInfo->yChar, NULL, &rect);
  8231.         }
  8232.         break;
  8233.  
  8234.     case SB_LINEUP:
  8235.     if (ptwInfo->curLine > 0) {
  8236.         --ptwInfo->curLine;
  8237.         ScrollWindow (hWnd, 0, ptwInfo->yChar, NULL, &rect);
  8238.  
  8239.         /*
  8240.          * ScrollWindow() invalidates part of the window, but does not
  8241.          * invalidate enough.  Do that here.
  8242.          */
  8243.         rect.top = 0;
  8244.         rect.bottom =  ptwInfo->yChar + MARGINE_TOP;
  8245.         rect.left = 0;
  8246.         rect.right = ptwInfo->xSize;
  8247.         InvalidateRect (hWnd, &rect, FALSE);
  8248.         }
  8249.         break;
  8250.  
  8251.     case SB_PAGEDOWN:
  8252.     ptwInfo->curLine += ptwInfo->nRows;
  8253.     if (ptwInfo->curLine > ptwInfo->lineCount - 1)
  8254.         ptwInfo->curLine = ptwInfo->lineCount - 1;
  8255.     fRepaint = TRUE;
  8256.         break;
  8257.  
  8258.     case SB_PAGEUP:
  8259.     ptwInfo->curLine -= ptwInfo->nRows;
  8260.     if (ptwInfo->curLine < 0)
  8261.         ptwInfo->curLine = 0;
  8262.     fRepaint = TRUE;
  8263.         break;
  8264.     
  8265.     case SB_THUMBPOSITION:
  8266.     case SB_THUMBTRACK:
  8267.     ptwInfo->curLine = nPos;
  8268.     fRepaint = TRUE;
  8269.         break;
  8270.  
  8271.     }
  8272.  
  8273.     SetScrollPos (hWnd, SB_VERT, (int)ptwInfo->curLine, TRUE);
  8274.     if (fRepaint)
  8275.     InvalidateRect (hWnd, NULL, TRUE);
  8276. }
  8277.  
  8278.  
  8279. /*
  8280.  * When the user presses the mouse button down to drag a selection, then
  8281.  * moves above or below the window we need to scroll the window.  
  8282.  * Mouse track events only occur when the mouse moves - they are not
  8283.  * adequate.  So, I install a timer, which sends a message to the window
  8284.  * which calls this function.
  8285.  *
  8286.  * ptwInfo->scrollDirect  indicates which direction the scrolling should
  8287.  * be done.
  8288.  */
  8289. LOCAL BOOL
  8290. TWScrollTimer (HWND hWnd)
  8291. {
  8292.     TextWndInfo        *ptwInfo;
  8293.     long        newcurLine;
  8294.     RECT        rect;
  8295.     long        lineLen;
  8296.     long        oldmarkLine, oldmarkChar;
  8297.     RECT        frame;
  8298.     
  8299.     
  8300.  
  8301.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  8302.     if (ptwInfo == NULL) {
  8303.     KillTimer (hWnd, TWS_TIMERID);
  8304.     return (FALSE);
  8305.     }
  8306.     
  8307.     if (ptwInfo->scrollDirect == TWS_OFF) {
  8308.     /* Timer should be off. */
  8309.     KillTimer (hWnd, TWS_TIMERID);
  8310.     return (FALSE);
  8311.     }
  8312.     
  8313.     frame.top = 0 + FRAME_3D_SIZE;
  8314.     frame.bottom =  ptwInfo->ySize - FRAME_3D_SIZE;
  8315.     frame.left = 0 + FRAME_3D_SIZE;
  8316.     frame.right = ptwInfo->xSize - FRAME_3D_SIZE;
  8317.  
  8318.     
  8319.     /*
  8320.      * Remember old mark.
  8321.      */
  8322.     oldmarkLine = ptwInfo->markLine;
  8323.     oldmarkChar = ptwInfo->markChar;
  8324.  
  8325.     
  8326.     /* 
  8327.      * Is scrolling going up or down?
  8328.      */
  8329.     if (ptwInfo->scrollDirect == TWS_UP) {
  8330.     /* 
  8331.      * Find new top line and move mark to left of top line. 
  8332.      */
  8333.     newcurLine = ptwInfo->curLine - 1;
  8334.     if (newcurLine < 0)
  8335.         newcurLine = 0;
  8336.     ptwInfo->markLine = newcurLine;
  8337.     ptwInfo->markChar = 0;
  8338.     }
  8339.     else if (ptwInfo->scrollDirect == TWS_DOWN) {
  8340.     /* 
  8341.      * Fine new top line and move mark to right of bottom line.
  8342.      */
  8343.     newcurLine = ptwInfo->curLine + 1;
  8344.     if (newcurLine > ptwInfo->lineCount - 1) 
  8345.         newcurLine = ptwInfo->lineCount - 1;
  8346.     ptwInfo->markLine = newcurLine + ptwInfo->nRows;
  8347.     
  8348.     /*
  8349.      * Handle the last line correctly.
  8350.      */
  8351.     if (ptwInfo->markLine >= ptwInfo->lineCount) {
  8352.         ptwInfo->markLine = ptwInfo->lineCount;
  8353.         ptwInfo->markChar = 0;
  8354.     }
  8355.     else 
  8356.         ptwInfo->markChar = strlen (*(ptwInfo->lines+ptwInfo->markLine));
  8357.     }
  8358.     
  8359.     /*
  8360.      * If window can be scrolled do it here.
  8361.      */
  8362.     if (newcurLine != ptwInfo->curLine) {
  8363.         
  8364.     /*
  8365.      * Update scroll bar and scroll the window.
  8366.      */
  8367.     SetScrollPos (hWnd, SB_VERT, (int)newcurLine, TRUE);
  8368.     ScrollWindow (hWnd, 0, 
  8369.         (int)(ptwInfo->curLine - newcurLine) * ptwInfo->yChar, 
  8370.         NULL, &frame);
  8371.     ptwInfo->curLine = newcurLine;
  8372.  
  8373.  
  8374.     /*
  8375.      * ScrollWindow() invalidates part of the window, but does not
  8376.      * invalidate enough.  Do that here.
  8377.      */
  8378.     if (oldmarkLine < ptwInfo->markLine ||
  8379.         (oldmarkLine == ptwInfo->markChar && 
  8380.             oldmarkChar < ptwInfo->markChar)) {
  8381.         rect.top = ((oldmarkLine - ptwInfo->curLine) * ptwInfo->yChar) + 
  8382.                 MARGINE_TOP;
  8383.         rect.bottom = ((ptwInfo->markLine - ptwInfo->curLine + 1) * 
  8384.                         ptwInfo->yChar) + MARGINE_TOP;
  8385.     }
  8386.     else {
  8387.         rect.top = ((ptwInfo->markLine - ptwInfo->curLine) * 
  8388.                         ptwInfo->yChar) + MARGINE_TOP;
  8389.         rect.bottom = ((oldmarkLine - ptwInfo->curLine + 1) * 
  8390.                         ptwInfo->yChar) + MARGINE_TOP;
  8391.     }
  8392.         
  8393.     rect.left = 0;
  8394.     rect.right = ptwInfo->xSize;
  8395.     InvalidateRect (hWnd, &rect, FALSE);
  8396.  
  8397.     UpdateWindow (hWnd);
  8398.     }
  8399. }
  8400.  
  8401.  
  8402.  
  8403.  
  8404.  
  8405. /*
  8406.  * Process a key down message.  Handle only virtual keys which can be
  8407.  * maped to scrolling operatons.
  8408.  */
  8409. LOCAL BOOL  
  8410. TWKeyDown (HWND hWnd, WORD key, DWORD keyData)
  8411. {
  8412.     BOOL    handled = TRUE;
  8413.     
  8414.     /* Special keys. */
  8415.     if (keyData & 0X20000000)
  8416.     return (FALSE);            /* Message NOT handled. */
  8417.  
  8418.     switch (key) {
  8419.     case VK_UP:
  8420.         TWScroll (hWnd, SB_LINEUP, 0);
  8421.         break;
  8422.         
  8423.     case VK_DOWN:
  8424.         TWScroll (hWnd, SB_LINEDOWN, 0);
  8425.         break;
  8426.         
  8427.     case VK_PRIOR:
  8428.         TWScroll (hWnd, SB_PAGEUP, 0);
  8429.         break;
  8430.     
  8431.     case VK_NEXT:
  8432.         TWScroll (hWnd, SB_PAGEDOWN, 0);
  8433.         break;
  8434.     
  8435.     case VK_HOME:
  8436.         TWScroll (hWnd, SB_TOP, 0);
  8437.         break;
  8438.         
  8439.     case VK_END:
  8440.         TWScroll (hWnd, SB_BOTTOM, 0);
  8441.         break;
  8442.  
  8443.     default:
  8444.         handled = FALSE;
  8445.         break;
  8446.     }
  8447.     return (handled);
  8448. }
  8449.  
  8450.  
  8451.  
  8452. /*
  8453.  * Convert a windows point to a Line and character.
  8454.  */
  8455. LOCAL void
  8456. TWPointToLC (TextWndInfo *ptwInfo, CORD xPos, CORD yPos, 
  8457.                 long *nLine, long *nChar)
  8458. {
  8459.     int            nRow, nCol;
  8460.     int            lineLen;
  8461.     BOOL        pastLast = FALSE;
  8462.     
  8463.     /*
  8464.      * Convert to row and column, staying out of top and left margines.
  8465.      */
  8466.     nRow = max (0, (yPos - MARGINE_TOP) / ptwInfo->yChar);
  8467.     nCol = max (0, (xPos - MARGINE_LEFT) / ptwInfo->xChar);
  8468.     
  8469.     /*
  8470.      * Convert to line.   If mouse is past bottom then point to one
  8471.      * past last line.
  8472.      */
  8473.     *nLine = ptwInfo->curLine + nRow;
  8474.     if (*nLine >= ptwInfo->lineCount) {
  8475.     *nLine = ptwInfo->lineCount;
  8476.     *nChar = 0;
  8477.     return;
  8478.     }
  8479.     lineLen = strlen (*(ptwInfo->lines + *nLine));
  8480.  
  8481.     
  8482.     /* If past right end of line, then start at first char of next */
  8483.     if (nCol > lineLen) {
  8484.     ++*nLine;
  8485.     *nChar = 0;
  8486.     }
  8487.     else
  8488.     *nChar = nCol;
  8489. }
  8490.  
  8491.  
  8492.  
  8493. /*
  8494.  * Mouse down.  Start selection.
  8495.  */
  8496. LOCAL BOOL  
  8497. TWMouseDown (HWND hWnd, int button, CORD xPos, CORD yPos, WPARAM keys)
  8498. {
  8499.     TextWndInfo        *ptwInfo;
  8500.     long        nLine;
  8501.     long        nChar;
  8502.     BOOL        wasPrevSel;
  8503.  
  8504.     
  8505.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  8506.     if (ptwInfo == NULL) 
  8507.     return (FALSE);
  8508.     
  8509.     /*
  8510.      * Only look at button 1.
  8511.      */
  8512.     if (button == 1) {
  8513.     wasPrevSel = (ptwInfo->markLine != ptwInfo->dotLine) ||
  8514.             (ptwInfo->markChar != ptwInfo->dotChar);
  8515.     TWPointToLC (ptwInfo, xPos, yPos, &nLine, &nChar);
  8516.     ptwInfo->markLine = nLine;
  8517.     ptwInfo->markChar = nChar;
  8518.     if (!(keys & MK_SHIFT)) {
  8519.         ptwInfo->dotLine = nLine;
  8520.         ptwInfo->dotChar = nChar;
  8521.         }
  8522.     SetCapture (hWnd);
  8523.     ptwInfo->tracking = TRUE;
  8524.     if (wasPrevSel || (keys & MK_SHIFT))
  8525.         InvalidateRect (hWnd, NULL, FALSE);
  8526.     return (TRUE);
  8527.     }
  8528.     return (FALSE);
  8529. }
  8530.  
  8531.  
  8532.  
  8533.  
  8534.  
  8535. /*
  8536.  * Mouse up, end selection
  8537.  */
  8538. LOCAL BOOL  
  8539. TWMouseUp (HWND hWnd, int button, CORD xPos, CORD yPos, WPARAM keys)
  8540. {
  8541.     TextWndInfo        *ptwInfo;
  8542.     long        nLine;
  8543.     long        nChar;
  8544.  
  8545.     
  8546.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  8547.     if (ptwInfo == NULL) 
  8548.     return (FALSE);
  8549.     
  8550.     /*
  8551.      * Only look at button 1.
  8552.      */
  8553.     if (button == 1) {
  8554.     TWPointToLC (ptwInfo, xPos, yPos, &nLine, &nChar);
  8555.     ptwInfo->markLine = nLine;
  8556.     ptwInfo->markChar = nChar;
  8557.     ReleaseCapture ();
  8558.     if (ptwInfo->scrollDirect != TWS_OFF) {
  8559.         ptwInfo->scrollDirect = TWS_OFF;
  8560.         KillTimer (hWnd, TWS_TIMERID);
  8561.         }
  8562.     ptwInfo->tracking = FALSE;
  8563.     return (TRUE);
  8564.     }
  8565.     return (FALSE);
  8566. }
  8567.  
  8568.  
  8569.  
  8570. /*
  8571.  * Track mouse down.  
  8572.  * If the mouse had gone above or below the window, enable the timer which
  8573.  * automatically scrolls the window.
  8574.  * If the mouse is in the window, move the mark and update the window.
  8575.  */
  8576. LOCAL BOOL  
  8577. TWMouseTrack (HWND hWnd, CORD xPos, CORD yPos)
  8578. {
  8579.     TextWndInfo        *ptwInfo;
  8580.     int            nRow, nCol;
  8581.     long        nLine, nChar;
  8582.     long        oldmarkLine, oldmarkChar;
  8583.     int            lineLen;
  8584.     RECT        rect;
  8585.  
  8586.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  8587.     if (ptwInfo == NULL) 
  8588.     return (FALSE);
  8589.  
  8590.     if (!ptwInfo->tracking)
  8591.     return (FALSE);
  8592.  
  8593.     
  8594.     
  8595.     
  8596.     /* 
  8597.      * Decide if the mouse in ABOVE, IN, or BELOW the window.
  8598.      */
  8599.     if (yPos < 0) {
  8600.     /* Mouse Above. */
  8601.     if (ptwInfo->scrollDirect != TWS_UP) {
  8602.         if (SetTimer (hWnd, TWS_TIMERID, TWS_TIMEOUT, NULL) != 0) 
  8603.         ptwInfo->scrollDirect = TWS_UP;
  8604.         }
  8605.     }
  8606.     else if (yPos > ptwInfo->ySize) {
  8607.     /* Mouse below. */
  8608.     if (ptwInfo->scrollDirect != TWS_DOWN) {
  8609.         if (SetTimer (hWnd, TWS_TIMERID, TWS_TIMEOUT, NULL) != 0) 
  8610.         ptwInfo->scrollDirect = TWS_DOWN;
  8611.         }
  8612.     }
  8613.     else {
  8614.     /* Mouse in window. */
  8615.     if (ptwInfo->scrollDirect != TWS_OFF) {
  8616.         ptwInfo->scrollDirect = TWS_OFF;
  8617.         KillTimer (hWnd, TWS_TIMERID);
  8618.         }
  8619.     oldmarkLine = ptwInfo->markLine;
  8620.     oldmarkChar = ptwInfo->markChar;
  8621.     TWPointToLC (ptwInfo, xPos, yPos, &nLine, &nChar);
  8622.     ptwInfo->markLine = nLine;
  8623.     ptwInfo->markChar = nChar;
  8624.  
  8625.  
  8626.     /*
  8627.      * Update just the line that changed. 
  8628.      */
  8629.     if (oldmarkLine < nLine ||
  8630.         (oldmarkLine == nLine && oldmarkChar < nChar)) {
  8631.         rect.top = ((oldmarkLine - ptwInfo->curLine) * ptwInfo->yChar) + 
  8632.                 MARGINE_TOP;
  8633.         rect.bottom = ((nLine - ptwInfo->curLine + 1) * ptwInfo->yChar) + 
  8634.                 MARGINE_TOP;
  8635.     }
  8636.     else {
  8637.         rect.top = ((nLine - ptwInfo->curLine) * ptwInfo->yChar) + 
  8638.                 MARGINE_TOP;
  8639.         rect.bottom = ((oldmarkLine - ptwInfo->curLine + 1) * ptwInfo->yChar)+
  8640.                 MARGINE_TOP;
  8641.     }
  8642.     rect.left = 0;
  8643.     rect.right = ptwInfo->xSize - FRAME_3D_SIZE;
  8644.     InvalidateRect (hWnd, &rect, FALSE);
  8645.     UpdateWindow (hWnd);
  8646.     }
  8647.     return (TRUE);
  8648. }
  8649.  
  8650.  
  8651.  
  8652.  
  8653.  
  8654. /*
  8655.  * Copy selection to clipboard.
  8656.  */
  8657. LOCAL BOOL  
  8658. TWEditCopy (HWND hWnd)
  8659. {
  8660.     TextWndInfo        *ptwInfo;
  8661.     long        selStartLine, selEndLine;
  8662.     long        selStartChar, selEndChar;
  8663.     long        selSize;
  8664.     long        len;
  8665.     HANDLE        hCB;
  8666.     char        *pCB;
  8667.     long        l;
  8668.  
  8669.     
  8670.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  8671.     if (ptwInfo == NULL) 
  8672.     return (FALSE);
  8673.  
  8674.  
  8675.     if (ptwInfo->dotLine < ptwInfo->markLine || 
  8676.         (ptwInfo->dotLine == ptwInfo->markLine  &&
  8677.          ptwInfo->dotChar < ptwInfo->markChar)) {
  8678.     selStartLine = ptwInfo->dotLine;
  8679.     selStartChar = ptwInfo->dotChar;
  8680.     selEndLine = ptwInfo->markLine;
  8681.     selEndChar = ptwInfo->markChar;
  8682.     }
  8683.     else {
  8684.     selStartLine = ptwInfo->markLine;
  8685.     selStartChar = ptwInfo->markChar;
  8686.     selEndLine = ptwInfo->dotLine;
  8687.     selEndChar = ptwInfo->dotChar;
  8688.     }
  8689.     /*
  8690.      * Count bytes in selection.
  8691.      */
  8692.     if (selStartLine == selEndLine) {
  8693.       selSize = selEndChar - selStartChar;
  8694.     }
  8695.     else {
  8696.     selSize = strlen (*(ptwInfo->lines + selStartLine)) - selStartChar + 2;
  8697.     for (l = selStartLine + 1; l < selEndLine; ++l) 
  8698.         selSize += strlen (*(ptwInfo->lines + l)) + 2;
  8699.         selSize += selEndChar;
  8700.     }
  8701.     
  8702.     if (selSize == 0)
  8703.     return (TRUE);
  8704.  
  8705.     if (OpenClipboard (ghTTYWnd)) {        /* ...and we get the CB. */
  8706.     if (EmptyClipboard ()) {        /* ...and clear previous CB.*/
  8707.         hCB = GlobalAlloc (GMEM_MOVEABLE, selSize+2);
  8708.         if (hCB != NULL) {
  8709.         pCB = GlobalLock (hCB);
  8710.  
  8711.         if (selStartLine == selEndLine) {
  8712.             /* Singe line, no CRLF. */
  8713.             len = selEndChar - selStartChar;
  8714.             memcpy (pCB, 
  8715.                 *(ptwInfo->lines + selStartLine) + selStartChar,
  8716.                 (size_t)len);
  8717.             pCB += len;
  8718.         }
  8719.         else {
  8720.             /* Copy first line with CRLF. */
  8721.             len = strlen (*(ptwInfo->lines + selStartLine)) - 
  8722.                                 selStartChar;
  8723.             memcpy (pCB, 
  8724.                 *(ptwInfo->lines + selStartLine) + selStartChar,
  8725.                 (size_t)len);
  8726.             pCB += len;
  8727.             *pCB++ = ASCII_CR;
  8728.             *pCB++ = ASCII_LF;
  8729.             
  8730.             /* Copy middle lines with CRLF. */
  8731.             for (l = selStartLine + 1; l < selEndLine; ++l) {
  8732.             len = strlen (*(ptwInfo->lines + l));
  8733.             memcpy (pCB, *(ptwInfo->lines + l), (size_t)len);
  8734.             pCB += len;
  8735.             *pCB++ = ASCII_CR;
  8736.             *pCB++ = ASCII_LF;
  8737.             }
  8738.             
  8739.             /* Copy last line without CRLF. */
  8740.             memcpy (pCB, *(ptwInfo->lines+selEndLine), 
  8741.                             (size_t)selEndChar);
  8742.             pCB += selEndChar;
  8743.         }
  8744.         
  8745.         /* Append null terminator. */
  8746.         *pCB++ = '\0';
  8747.         
  8748.         GlobalUnlock (hCB);
  8749.  
  8750.         if (SetClipboardData (CF_TEXT, hCB) == NULL)
  8751.           /* Failed!  Free the data. */
  8752.           GlobalFree (hCB);
  8753.         }
  8754.     }
  8755.     CloseClipboard (); 
  8756.     }
  8757.  
  8758.     return (FALSE);
  8759. }
  8760.  
  8761.  
  8762.  
  8763.  
  8764. LOCAL void
  8765. TWSetSize (HWND hWnd, UINT wParam, UINT height, UINT width)
  8766. {
  8767.     TextWndInfo        *ptwInfo;
  8768.     
  8769.     
  8770.     if (wParam == SIZE_MINIMIZED)
  8771.     return;
  8772.     
  8773.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  8774.     if (ptwInfo == NULL) 
  8775.     return;
  8776.  
  8777.  
  8778.     /* Calculate new number of rows and columns. */
  8779.     ptwInfo->xSize = width;
  8780.     ptwInfo->ySize = height;
  8781.     ptwInfo->nCols = (width  - (2 * MARGINE_LEFT)) / ptwInfo->xChar;
  8782.     ptwInfo->nRows = (height - (2 * MARGINE_TOP))  / ptwInfo->yChar;
  8783.     
  8784.     InvalidateRect (hWnd, NULL, FALSE);
  8785.     return;
  8786. }
  8787.  
  8788.  
  8789.  
  8790. LOCAL void
  8791. TWPrint (HWND hWnd)
  8792. {
  8793.     TextWndInfo        *ptwInfo;
  8794.     int            rc;
  8795. #define DESC_LEN    180
  8796.     char        description[DESC_LEN+1];
  8797.     char        **line;
  8798.     UINT        i;
  8799.     
  8800.     
  8801.     ptwInfo = (TextWndInfo *) GetWindowLong (hWnd, GWL_PTEXTINFO);
  8802.     
  8803.     GetWindowText (hWnd, description, DESC_LEN);
  8804.  
  8805.     rc = mswin_print_ready ((WINHAND)hWnd, description);
  8806.     if (rc != 0) {
  8807.     if (rc != PE_USER_CANCEL) {
  8808.         strcpy (description, "Printing failed:  ");
  8809.         strcat (description, mswin_print_error (rc));
  8810.         MessageBox (hWnd, description, "Print Failed", 
  8811.                 MB_OK | MB_ICONEXCLAMATION);
  8812.     }
  8813.     return;
  8814.     }
  8815.     
  8816.     
  8817.     for (line = ptwInfo->lines, i = 0; i < ptwInfo->lineCount; ++line, ++i) {
  8818.     mswin_print_text (*line);
  8819.     mswin_print_text ("\r\n");
  8820.     }
  8821.     
  8822.     mswin_print_done ();
  8823. }
  8824.         
  8825.  
  8826.  
  8827.  
  8828.  
  8829.  
  8830.  
  8831. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  8832.  *
  8833.  *                  Character Queue
  8834.  *
  8835.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  8836.  
  8837.  
  8838. typedef struct {
  8839.     WORD    flags;
  8840.     WORD    c;
  8841. } CQEntry;
  8842.  
  8843. LOCAL CQEntry CQBuffer [CHARACTER_QUEUE_LENGTH];
  8844. LOCAL int CQHead;
  8845. LOCAL int CQTail;
  8846. LOCAL int CQCount;
  8847.  
  8848.  
  8849. /*---------------------------------------------------------------------------
  8850.  *  BOOL  CQInit ()
  8851.  *
  8852.  *  Description:
  8853.  *        Initialize the Character queue.
  8854.  *
  8855.  *  Parameters:
  8856.  *
  8857.  *
  8858. /*--------------------------------------------------------------------------*/
  8859. LOCAL void
  8860. CQInit (void)
  8861. {
  8862.     CQHead = 0;
  8863.     CQTail = 0;
  8864.     CQCount = 0;
  8865. }
  8866.  
  8867.  
  8868. /*---------------------------------------------------------------------------
  8869.  *  BOOL  CQAvailable (void)
  8870.  *
  8871.  *  Description:
  8872.  *        Return TRUE if there are characters in the queue.
  8873.  *
  8874.  *  Parameters:
  8875.  *
  8876.  *
  8877. /*--------------------------------------------------------------------------*/
  8878.  
  8879. LOCAL BOOL
  8880. CQAvailable (void)
  8881. {
  8882.     return (CQCount > 0);
  8883. }
  8884.  
  8885.  
  8886.  
  8887. /*---------------------------------------------------------------------------
  8888.  *  BOOL  CQAdd (WORD c, DWORC keyData)
  8889.  *
  8890.  *  Description:
  8891.  *        Add 'c' to the end of the character queue.
  8892.  *
  8893.  *  Parameters:
  8894.  *        return true if successfull.
  8895.  *
  8896. /*--------------------------------------------------------------------------*/
  8897.  
  8898. LOCAL BOOL
  8899. CQAdd (WORD c, DWORD keyData)
  8900. {
  8901.     if (CQCount == CHARACTER_QUEUE_LENGTH)
  8902.         return (FALSE);
  8903.     
  8904.     
  8905.     CQBuffer[CQTail].flags = 0;
  8906.     if ((keyData & 0x80000000) == 0)
  8907.         CQBuffer[CQTail].flags |= CQ_FLAG_DOWN;
  8908.     if (keyData & 0x01000000)
  8909.         CQBuffer[CQTail].flags |= CQ_FLAG_EXTENDED;
  8910.     if (keyData & 0x20000000)
  8911.         CQBuffer[CQTail].flags |= CQ_FLAG_ALT;
  8912.     CQBuffer[CQTail].c = c;
  8913.     CQTail = (CQTail + 1) % CHARACTER_QUEUE_LENGTH;
  8914.     ++CQCount;
  8915.     return (TRUE);
  8916. }
  8917.  
  8918.  
  8919.  
  8920. /*---------------------------------------------------------------------------
  8921.  *  BOOL  CQAddUniq (WORD c, DWORC keyData)
  8922.  *
  8923.  *  Description:
  8924.  *        Add 'c' to the end of the character queue, only if
  8925.  *        there is no other 'c' in the queue
  8926.  *
  8927.  *  Parameters:
  8928.  *        return true if successfull.
  8929.  *
  8930. /*--------------------------------------------------------------------------*/
  8931.  
  8932. LOCAL BOOL
  8933. CQAddUniq (WORD c, DWORD keyData)
  8934. {
  8935.     int        i;
  8936.     int        pos;
  8937.     
  8938.     if (CQCount == CHARACTER_QUEUE_LENGTH)
  8939.         return (FALSE);
  8940.     
  8941.     pos = CQHead;
  8942.     for (i = 0; i < CQCount; ++i) {
  8943.         if (CQBuffer[pos].c == c)
  8944.         return (FALSE);
  8945.         pos = (pos + 1) % CHARACTER_QUEUE_LENGTH;
  8946.     }
  8947.     return (CQAdd (c, keyData));
  8948. }
  8949.  
  8950.  
  8951.  
  8952.  
  8953. /*---------------------------------------------------------------------------
  8954.  *  int  CQGet ()
  8955.  *
  8956.  *  Description:
  8957.  *        Return the next byte from the head of the queue.  If there is
  8958.  *        no byte available, returns 0, which is indistinquishable from 
  8959.  *        '\0'.  So it is a good idea to call CQAvailable first.
  8960.  *
  8961.  *  Parameters:
  8962.  *        none.
  8963.  *
  8964. /*--------------------------------------------------------------------------*/
  8965.  
  8966. LOCAL WORD
  8967. CQGet ()
  8968. {
  8969.     WORD    c;
  8970.  
  8971.     if (CQCount == 0)
  8972.     return (0);
  8973.  
  8974.     c = CQBuffer[CQHead].c;
  8975.     CQHead = (CQHead + 1) % CHARACTER_QUEUE_LENGTH;
  8976.     --CQCount;
  8977.     return (c);
  8978. }
  8979.  
  8980.  
  8981. #if 0
  8982. /*---------------------------------------------------------------------------
  8983.  *
  8984.  *  LOCAL int MapVKtoMS (WORD c, WORD flags);
  8985.  *
  8986.  * Description:
  8987.  *    Map key received in WM_CHAR message to intermediate character code.
  8988.  *      which latter gets maped to a pico or pine character code.
  8989.  */
  8990. LOCAL int
  8991. MapVKtoMS (WORD c, WORD flags)
  8992. {
  8993.     /* Special keys. */
  8994.     if (flags & CQ_FLAG_ALT)
  8995.     return (MSWIN_KEY_NODATA);
  8996.  
  8997.     if (flags & CQ_FLAG_EXTENDED) {
  8998.     switch (c) {
  8999.         case VK_UP:            return (MSWIN_KEY_UP);
  9000.         case VK_DOWN:        return (MSWIN_KEY_DOWN);
  9001.         case VK_RIGHT:        return (MSWIN_KEY_RIGHT);
  9002.         case VK_LEFT:        return (MSWIN_KEY_LEFT);
  9003.         case VK_PRIOR:        return (MSWIN_KEY_PREVPAGE);
  9004.         case VK_NEXT:        return (MSWIN_KEY_NEXTPAGE);
  9005.         case VK_HOME:        return (MSWIN_KEY_HOME);
  9006.         case VK_END:        return (MSWIN_KEY_END);
  9007.         case VK_DELETE:        return (MSWIN_KEY_DELETE);
  9008.         case VK_F1:            return (MSWIN_KEY_F1);
  9009.         case VK_F2:            return (MSWIN_KEY_F2);
  9010.         case VK_F3:            return (MSWIN_KEY_F3);
  9011.         case VK_F4:            return (MSWIN_KEY_F4);
  9012.         case VK_F5:            return (MSWIN_KEY_F5);
  9013.         case VK_F6:            return (MSWIN_KEY_F6);
  9014.         case VK_F7:            return (MSWIN_KEY_F7);
  9015.         case VK_F8:            return (MSWIN_KEY_F8);
  9016.         case VK_F9:            return (MSWIN_KEY_F9);
  9017.         case VK_F10:        return (MSWIN_KEY_F10);
  9018.         case VK_F11:        return (MSWIN_KEY_F11);
  9019.         case VK_F12:        return (MSWIN_KEY_F12);
  9020.         default:            return (MSWIN_KEY_NODATA);
  9021.         }
  9022.     }
  9023.     
  9024.     /* Normal keys. */
  9025.     return (c);
  9026. }
  9027. #endif
  9028.  
  9029.  
  9030.  
  9031.  
  9032. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  9033.  *
  9034.  *                  Mouse Event Queue
  9035.  *
  9036.  *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
  9037.  
  9038.  
  9039.  
  9040. LOCAL MEvent MQBuffer [MOUSE_QUEUE_LENGTH];
  9041. LOCAL int MQHead;
  9042. LOCAL int MQTail;
  9043. LOCAL int MQCount;
  9044.  
  9045.  
  9046. /*---------------------------------------------------------------------------
  9047.  *  BOOL  MQInit ()
  9048.  *
  9049.  *  Description:
  9050.  *        Initialize the Character queue.
  9051.  *
  9052.  *  Parameters:
  9053.  *
  9054.  *
  9055. /*--------------------------------------------------------------------------*/
  9056. LOCAL void
  9057. MQInit (void)
  9058. {
  9059.     MQHead = 0;
  9060.     MQTail = 0;
  9061.     MQCount = 0;
  9062. }
  9063.  
  9064.  
  9065. /*---------------------------------------------------------------------------
  9066.  *  BOOL  MQAvailable (void)
  9067.  *
  9068.  *  Description:
  9069.  *        Return TRUE if there are characters in the queue.
  9070.  *
  9071.  *  Parameters:
  9072.  *
  9073.  *
  9074. /*--------------------------------------------------------------------------*/
  9075.  
  9076. LOCAL BOOL
  9077. MQAvailable (void)
  9078. {
  9079.     return (MQCount > 0);
  9080. }
  9081.  
  9082.  
  9083.  
  9084. /*---------------------------------------------------------------------------
  9085.  *  BOOL  MQAdd ()
  9086.  *
  9087.  *  Description:
  9088.  *        Add 'c' to the end of the character queue.
  9089.  *
  9090.  *  Parameters:
  9091.  *        return true if successfull.
  9092.  *
  9093. /*--------------------------------------------------------------------------*/
  9094.  
  9095. LOCAL BOOL
  9096. MQAdd (int mevent, int button, int nRow, int nColumn, int keys, int flags)
  9097. {
  9098.     int        i;
  9099.     int        c;
  9100.     BOOL    found = FALSE;
  9101.  
  9102.     
  9103.     /*
  9104.      * Find a queue insertion point.
  9105.      */
  9106.     if (flags & MSWIN_MF_REPLACING) {
  9107.     /* Search for same event on queue. */
  9108.     for (   i = MQHead, c = MQCount; 
  9109.             c > 0; 
  9110.         i = (i + 1) % MOUSE_QUEUE_LENGTH, --c) {
  9111.         if (MQBuffer[i].event == mevent) {
  9112.         found = TRUE;
  9113.         break;
  9114.         }
  9115.         }
  9116.     }
  9117.     if (!found) {
  9118.     if (MQCount == MOUSE_QUEUE_LENGTH)
  9119.         return (FALSE);
  9120.         i = MQTail;
  9121.     MQTail = (MQTail + 1) % MOUSE_QUEUE_LENGTH;
  9122.     ++MQCount;
  9123.     }
  9124.     
  9125.  
  9126.     /*
  9127.      * Record data.
  9128.      */
  9129.     MQBuffer[i].event = mevent;
  9130.     MQBuffer[i].button = button;
  9131.     MQBuffer[i].nRow = nRow;
  9132.     MQBuffer[i].nColumn = nColumn;
  9133.     MQBuffer[i].keys = keys;
  9134.     MQBuffer[i].flags = flags;
  9135.     
  9136.     /*
  9137.      * Keep record of last mouse position.
  9138.      */
  9139.     gMTEvent = MQBuffer[i];
  9140.     
  9141.     return (TRUE);
  9142. }
  9143.  
  9144.  
  9145.  
  9146.  
  9147.  
  9148. /*---------------------------------------------------------------------------
  9149.  *  BOOL  MQGet ()
  9150.  *
  9151.  *  Description:
  9152.  *        Return the next byte from the head of the queue.  If there is
  9153.  *        no byte available, returns 0, which is indistinquishable from 
  9154.  *        '\0'.  So it is a good idea to call MQAvailable first.
  9155.  *
  9156.  *  Parameters:
  9157.  *        none.
  9158.  *
  9159. /*--------------------------------------------------------------------------*/
  9160.  
  9161. LOCAL BOOL
  9162. MQGet (MEvent * pMouse)
  9163. {
  9164.     if (MQCount == 0)
  9165.     return (FALSE);
  9166.  
  9167.     
  9168.     *pMouse = MQBuffer[MQHead];
  9169.     MQHead = (MQHead + 1) % MOUSE_QUEUE_LENGTH;
  9170.     --MQCount;
  9171.     return (TRUE);
  9172. }
  9173.  
  9174.  
  9175.  
  9176.  
  9177.  
  9178.  
  9179. void 
  9180. AssertFail    (char *str, char *file, int line, int msgbox)
  9181. {
  9182.     /* static to avoid risk of stack overflow */
  9183.     static int    inAssert    = 0;
  9184.     static int    doBreak        = 1;
  9185.     char    *    filename;
  9186.     int            ret;
  9187.  
  9188.  
  9189.  
  9190.     /* for now, strip off path from filename */
  9191.     filename = strrchr(file, '\\');
  9192.     if (filename)
  9193.         filename++;
  9194.     else
  9195.         filename = file;
  9196.  
  9197.     wsprintf(TempBuf, "Assert(%s) failed!  %s:%d\n", 
  9198.                 str, filename, line);
  9199.  
  9200.     inAssert++;
  9201.  
  9202.  
  9203. retry:
  9204.  
  9205.     /*    Unfortunately, there are certain times when attempting to
  9206.      *    display a message box will cause the system to crash (e.g.,
  9207.      *    when handling certain messages in a WndProc).
  9208.      *
  9209.      *    Message box was previously TaskModal, but this didn't work
  9210.      *    well because the client AIM could keep sending requests.
  9211.      *    SystemModal shuts the whole system down but at least it
  9212.      *    guarantees some degree of consistency, and makes debugging
  9213.      *    a bit easier.
  9214.      */
  9215.     ret = MessageBox (NULL, TempBuf, NULL, 
  9216.                     MB_ABORTRETRYIGNORE | MB_SYSTEMMODAL );
  9217.  
  9218.  
  9219.     if (ret == IDABORT) {
  9220.         ret = MessageBox(NULL, 
  9221.                 "AbortIng may not properly free resources.  Are you sure?",
  9222.                 "Assertion Abort",
  9223.                 MB_YESNO | MB_TASKMODAL | MB_ICONSTOP);
  9224.  
  9225.         if (ret == IDYES) {
  9226.             /*
  9227.              *    Cause a GPF in case DrWatson is running
  9228.              */
  9229.             char *p = NULL;
  9230.             *p = 1;
  9231.         }
  9232.         else 
  9233.             goto retry;
  9234.     }
  9235.  
  9236.     /* retry is not (and will never be) hooked up, but it's
  9237.      * easier to use the standard dialog box than create
  9238.      * our own.  if retry is selected, just report the
  9239.      * error again.
  9240.      */
  9241.     if (ret == IDRETRY)
  9242.         goto retry;
  9243.     inAssert--;
  9244. }
  9245.